Chuyển đến nội dung chính

dsh-session-control

Đã xác minh

dsh-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.patchcordis.patch.ymldsh.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]