dsh-session-control
Đã xác minhdsh-session-control · v1.1.0 · MIT · Giao diện web
DSH web GUI session management and service control: delete sessions (including ungrouped ones, with graceful agent termination) from a Settings page, plus restart / shutdown the dsh web host. · dsh Web GUI 会话管理与服务控制:设置页一键删除会话(含未分组、优雅终止 agent)+ 重启/关闭宿主服务。
Cài đặt
dsh plugin add dsh-session-control Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.
Thẻ
Tác giả
Readme
dsh-session-control
DSH web GUI 会话管理与服务控制插件:设置页「会话管理」一键删除会话(含未分组 / 已归档 / 空会话,运行中的会话先优雅终止再物理删除),设置页「服务控制」重启 / 关闭 dsh Web 宿主(隐藏控制台,重启后页面自动恢复)。
一个包、两个功能,零修改 dsh 安装文件,与现有补丁互不干扰(路由挂 /dsh-sc/*,不占 RPC 路由)。
安装
发布到 npm 后:
dsh plugin --profile web add dsh-session-control
本地未发布时用 link 安装:
dsh plugin --profile web add link:D:\WorkSpacee\project-006-dsh-web插件化\code\plugin\dsh-session-control
安装后重启 dsh web,设置页出现「会话管理」(order 30)与「服务控制」(order 40)两个分区。
使用
- 会话管理:按工作区分组列出全部会话(含未分组桶),每行显示运行状态、归档标记与最近活动时间,垃圾桶按钮弹确认框。删除 = 优雅终止 live agent → 等待最终落盘(轮询
sessionPersistence.list())→ 从各 workspace 摘除账目 → 清归档标记 → 物理删除会话目录 → 发出workspace/session-deleted(宿主据此广播host/session-removed帧,侧边栏与所有标签页同步消失)。客户端删除成功后调用公开的sessions.refresh()重拉列表兜底;遇到session-not-found(会话已在别处删除)也立即刷新列表,幽灵条目不再残留。- 优雅终止是双层的,不依赖补丁:优先用
agentLoop.ownership.liveById(已打补丁 / 新版 dsh 原生带disposeById);缺失时回退到公开的AgentHandle——插件在宿主启动时包装ctx.agents.create/resume,把每个{ agent, dispose }句柄按 sessionId 捕获(lib/agent-handles.js),删除时直接handle.dispose()。因此未打补丁的 dsh(如 rc.2)也能删除空闲/挂载中的会话,不再误报「该会话正在使用中」。
- 优雅终止是双层的,不依赖补丁:优先用
- 服务控制:重启 = 分离拉起内置
web-restarter.mjs→ 3.5s 后优雅 dispose 自身 → 4s 重启器兜底强杀 → 隐藏控制台(non-detached powershell +Start-Process -WindowStyle Hidden)拉起新宿主 → 冒烟检查端口;客户端轮询 origin,观测到宕机窗口后等新宿主就绪再location.reload()。关闭 = 1s 后 dispose + exit,5s 硬退出兜底。
安全
所有路由仅接受同源回环请求(127.0.0.1 / ::1 / ::ffff:127.0.0.1,拒绝任何转发链头,Origin 必须与 Host 同源),与 dshmarket 的 trustedRestartRequest 同一纪律。
架构
| 文件 | 职责 |
|---|---|
package.json |
dsh.bundle.patch → cordis.patch.yml;dsh.client.inject 声明 client 依赖(connection/runtime/locale/ui-settings);exports["./client"] |
cordis.patch.yml |
插入 profile 层栈的插件条目 |
lib/index.js |
host 插件入口:ctx.inject(["webServer","workspaceRegistry","sessionPersistence"]),安装 AgentHandle 捕获并挂路由 |
lib/agent-handles.js |
包装 ctx.agents.create/resume 捕获 AgentHandle 并按 sessionId 索引;disposeById 优雅终止(未打补丁 dsh 的终止路径) |
lib/routes.js |
`POST /dsh-sc/delete |
lib/delete-session.js |
会话删除流程(对齐 project-006 补丁语义,全部走公有面 + 运行时探测降级) |
lib/lifecycle.js |
重启器拉起(保留当前 argv)与优雅关闭调度 |
lib/web-restarter.mjs |
分离重启器(隐藏控制台纪律,禁止改动 spawn 方式) |
client/client.js |
__ModuleLoader__ bundle:两个 settings.section + zh/en 文案 + 自注入 CSS |
非公开面(ownership.liveById、registry 内部 state 助手)全部 optional-chain + 优雅降级:有就用最贴近补丁的原生路径,没有就回退到公开的 AgentHandle,缺失时功能降级为「尽力而为 / 明确报错」而非崩溃。
开发
node --check lib\*.js lib\*.mjs client\client.js # 静态校验
node test\verify-client.cjs # 客户端 bundle 结构校验
隔离 E2E(不碰真实 profile / 会话):
$env:DSH_HOME = "D:\Temp\opencode\dsh-e2e"
dsh plugin --profile e2e add link:D:\...\dsh-session-control
# 编辑 D:\Temp\opencode\dsh-e2e\profiles\e2e\package.json 的 bundles 加上 @deepseek-ai/dsh-web-app
node "D:\Program Files\nodejs\node_global\node_modules\@deepseek-ai\dsh\lib\bin.js" --profile e2e --port 18080
伪造会话 artifact(zstd,header 的 cwd 必须与目录一致,目录名规则 --<encoded-cwd>--/<id>/):
const h = JSON.stringify({type:"session",version:0,id:"e2e-session-0001",createdAt:Date.now(),delegationDepth:0,cwd:"e2e-fake"});
fs.writeFileSync(".../sessions/--e2e-fake--/e2e-session-0001/session.jsonl.zstd", zlib.zstdCompressSync(Buffer.from(h+"\n")));
发布
npm publish --access public
版本
- 1.1.0:优雅终止不依赖补丁——
agentLoop.ownership.liveById缺失(未打补丁 / rc.2)时,回退到包装ctx.agents.create/resume捕获的公开AgentHandle来按会话终止 agent,修复「空闲会话误报正在使用中,无法删除」。zero 修改 dsh 文件。 - 1.0.1:修复删除会话失败——客户端改用公开的
sessions.refresh()(不再调用私有的recordMutation);session-not-found时刷新列表移除幽灵条目;host 侧删除成功后发出workspace/session-deleted,让所有客户端经host/session-removed帧同步移除。 - 1.0.0:会话删除 + 服务控制,目标
@deepseek-ai/[email protected]。