🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

会话拖拽归类 lanscer/dsh-workspace-drag

DeepSeek Harness
lanscer39 天前有提交已提供中文文档扫描:含敏感能力

DSH Web UI 插件——把会话拖到任意工作区就能整理

30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/9/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

该插件未发布到 npm,按作者文档从 GitHub 源安装即可(静态检查只覆盖 npm 路径,不代表插件不可用)。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add lanscer/dsh-workspace-drag
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · ui
装得上吗
实装验证未通过(dependency_conflict),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 39 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(dependency_conflict · 2026/11/2) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-workspace-drag(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=18 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/12 09:39:38

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 43 处,展示前 30 条)
  • 读取本地文件
    lib/index.js:137
    entries = readdirSync(dir)
  • 读取本地文件
    lib/index.js:183
    if (!existsSync(path)) return { enabled: DEFAULT_ENABLED }
  • 读取本地文件
    lib/index.js:184
    const raw = JSON.parse(readFileSync(path, 'utf8'))
  • 写入本地文件
    lib/index.js:195
    mkdirSync(dirname(path), { recursive: true })
  • 写入本地文件
    lib/index.js:196
    writeFileSync(path, JSON.stringify(config, null, 2) + '\n')
  • 执行外部命令固定命令
    lib/index.js:271
    const found = execSync('which zstd', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] }).trim()
  • 读取本地文件
    lib/index.js:272
    if (found !== '' && existsSync(found)) return found
  • 读取本地文件
    lib/index.js:281
    if (existsSync(candidate)) return candidate
  • 执行外部命令来自配置/变量
    lib/index.js:298
    return execFileSync(ZSTD_BIN, args, {
  • 读取本地文件
    lib/index.js:309
    if (!isZstdPath(filePath)) return readFileSync(filePath)
  • 写入本地文件
    lib/index.js:421
    mkdirSync(to, { recursive: true })
  • 写入本地文件
    lib/index.js:427
    else copyFileSync(src, dst)
  • 删除本地文件
    lib/index.js:690
    if (existsSync(stagedLog)) rmSync(stagedLog)
  • 写入本地文件
    lib/index.js:691
    writeFileSync(stagedLog, rewritten)
  • 写入本地文件
    lib/index.js:704
    mkdirSync(newProjectDir, { recursive: true })
  • 删除本地文件递归
    lib/index.js:705
    if (existsSync(newSessionDir)) rmSync(newSessionDir, { recursive: true, force: true })
  • 删除本地文件递归
    lib/index.js:708
    rmSync(staging, { recursive: true, force: true })
  • 删除本地文件递归
    lib/index.js:735
    try { rmSync(newSessionDir, { recursive: true, force: true }) } catch { }
  • 删除本地文件递归
    lib/index.js:765
    rmSync(oldSessionDir, { recursive: true, force: true })
  • 发起网络请求
    lib/client.js:74
    return fetch(CONFIG_API, { cache: "no-store" })
  • 发起网络请求
    lib/client.js:89
    return fetch(CONFIG_API, {
  • 发起网络请求
    lib/client.js:301
    return fetch(MOVE_API, {
  • 读取本地文件
    install-plugin.mjs:56
    if (!existsSync(PKG_JSON)) {
  • 读取本地文件
    install-plugin.mjs:64
    return JSON.parse(readFileSync(PKG_JSON, 'utf8'))
  • 读取本地文件
    install-plugin.mjs:72
    if (alreadyRegistered() && existsSync(NM_LINK)) {
  • 写入本地文件
    install-plugin.mjs:81
    try { copyFileSync(PKG_JSON, backupPath) } catch { }
  • 写入本地文件
    install-plugin.mjs:86
    writeFileSync(PKG_JSON, JSON.stringify(profile, null, 2) + '\n', 'utf8')
  • 写入本地文件
    install-plugin.mjs:90
    mkdirSync(NM_DIR, { recursive: true })
  • 读取本地文件
    install-plugin.mjs:92
    if (existsSync(NM_LINK)) rmSync(NM_LINK, { recursive: true, force: true })
  • 删除本地文件递归
    install-plugin.mjs:92
    if (existsSync(NM_LINK)) rmSync(NM_LINK, { recursive: true, force: true })
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-client-ui-conversation@deepseek-ai/dsh-client-ui-settings
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 拖拽会话至工作区
  • 会话归类整理

README

由 DeepSeek 最新模型翻译生成
dsh-workspace-drag DSH Web UI 插件 — 把对话拖到任意工作区即可归类整理 拖起会话行 → 悬停工作区组 → 迁移(cwd + 文件 + 归属账本) DSH Web UI 插件 — 在侧边栏(分组视图)里,把一个历史对话直接拖到另一个工作区的标题(或该组内任意会话行)上松开,就能把这个对话归到目标工作区,实现跨工作区的对话分类整理。无感拖拽:没有弹窗、没有中间面板,拖到哪就归到哪。 安装 从本 GitHub 仓库用 DSH 官方插件命令安装: dsh plugin --profile web add github:lanscer/dsh-workspace-drag 本地 checkout 则可一键安装进 DSH web profile。请先在插件目录内运行(包含 package.json 的那个文件夹——克隆 dsh-workspace-drag 后先 cd 进去): npm run install:plugin 或直接执行(跨平台,基于 Node.js): node install-plugin.mjs 支持 Windows(PowerShell)、macOS、Linux——安装器是纯 Node.js 脚本,不依赖 bash 或 PowerShell 专属语法。
展开完整文档(README 剩余 1 节)
dsh-workspace-drag

DSH Web UI 插件 — 把对话拖到任意工作区即可归类整理

拖起会话行 → 悬停工作区组 → 迁移(cwd + 文件 + 归属账本)

DSH Web UI 插件 — 在侧边栏(分组视图)里,把一个历史对话直接拖到另一个工作区的标题(或该组内任意会话行)上松开,就能把这个对话归到目标工作区,实现跨工作区的对话分类整理。无感拖拽:没有弹窗、没有中间面板,拖到哪就归到哪。

安装

从本 GitHub 仓库用 DSH 官方插件命令安装:

dsh plugin --profile web add github:lanscer/dsh-workspace-drag

本地 checkout 则可一键安装进 DSH web profile。请先在插件目录内运行(包含 package.json 的那个文件夹——克隆 dsh-workspace-drag 后先 cd 进去):

npm run install:plugin

或直接执行(跨平台,基于 Node.js):

node install-plugin.mjs

支持 Windows(PowerShell)、macOS、Linux——安装器是纯 Node.js 脚本,不依赖 bash 或 PowerShell 专属语法。

脚本会把插件注册进 ~/.dsh/profiles/web(Windows 上为 %USERPROFILE%\.dsh\profiles\web):在 profile 的 package.json 添加 link: 依赖,并在 node_modules 下建立符号链接。
不触发 pnpm install,从而绕过 pnpm 的 minimumReleaseAge 策略(该策略会拦截发布不足 24 小时的依赖)。幂等——已安装时重复执行会直接跳过。

⚠️ Windows 注意事项
- 必须在克隆下来的插件文件夹内运行,不要在用户主目录运行——npm run 需要当前目录有 package.json(报错 ENOENT ... C:\Users\\package.json 就是因为在错误目录运行)。
- 建符号链接使用 junction 类型,Windows 无需开启开发者模式或管理员权限。
- 若符号链接被策略拦截,link: 依赖仍会写入 profile,此时再用 dsh plugin --profile web add link: 补完即可。

安装后生效方式:
- 纯客户端改动:刷新浏览器页面
- 宿主端改动:重启 dsh web

注意:插件依赖 zstd CLI(见依赖)。

功能

- 无感跨工作区拖拽:侧边栏分组视图中,拖起会话行 → 悬停在另一个工作区组(标题或组内任意会话行)上高亮 → 松开即迁移。
- 无浮动面板、无确认弹窗;同工作区内的拖放仍走 DSH 原生排序,互不干扰。
- 成功后短暂提示,会话立即出现在目标工作区。
- 开关:在 设置 → 拖拽归类对话 页面一键启用/关闭;关闭后拖拽不生效(高亮/迁移都被禁用)。
- 安全:
- Agent 正在运行中的会话不能移动(基于 agent 状态精确判断,不再用粗暴的 30 秒 mtime 窗口)。
- 刚聊完的会话:拖拽后宿主端自动等待写入静止(最长 15 秒)再迁移,一次拖拽即完成,无需"等一会再拖一次"。
- 迁移在宿主端先复制 + 校验新文件,确认无误后才删除旧目录,失败不丢数据。
- 移动的是会话日志文件的物理位置 + 头部 cwd 字段,并同步工作区注册表归属账本与内存状态(live header / 持久化写入句柄 / 注册表索引),移动后可继续在该会话中对话。
- 写入句柄重定向(ENOENT 修复):DSH 的 jsonl 后端把每次追加的落盘路径取自打开中的写入句柄的 header.cwd(JsonlSessionHandle.persistContiguous → appendLines → logPath(root, meta.cwd, id)),并按 id 通过同一句柄路由实时事件(tracker.writers)。旧版只重写文件与 session 对象、没动该句柄,句柄仍指向旧目录,于是下一次对话失败于 ENOENT: no such file or directory, open '/session.v3.jsonl.zstd'。现在插件会在删除旧目录之前重写该句柄的 header;若句柄无法重定向则放弃移动(原目录不动、已发布的副本回滚)。

原理(数据层)

- DSH 每个会话的工作区身份 = 其头部 cwd(绝对目录路径)。
- 会话存储于 ~/.dsh/sessions///session.v.jsonl[.zstd]。
格式版本随 dsh 升级推进:0.1.5 起为 v3(session.v3.jsonl[.zstd]),0.1.7-rc.1 起为 v4
(session.v4.jsonl[.zstd]);最初版本的 session.jsonl[.zstd](无 vN 段,即版本 0)
仍会保留在磁盘上。
- 迁移 = 把会话目录移动到目标工作区的 projectKey 目录下 + 重写第一行(header)的 cwd + 用 ctx.workspaceRegistry 的 detach/attach 更新工作区归属账本。
- 格式版本是"发现"出来的,不是写死的:插件按规范文件名
^session(?:\.v([1-9][0-9]))?\.jsonl(\.zstd)?$ 扫描会话目录,取版本号最大的一代,并重写
目录内全部世代(当前代 + 旧代 + 遗留 session.jsonl[.zstd])的 header cwd。这样 dsh 再升到 v5/v6 也无需改插件代码;备份文件(.bak-、.pre-fix-、.corrupt-*)因不符合规范命名而被忽略。dsh 持久化层会按 (cwd, id) 计算期望路径,若磁盘实际位置不符即报 corrupt session log: header id ... and cwd identify ...——所以每一代都必须重写。
- sessionPersistence.list() 返回契约:dsh 0.1.7-rc.1 起返回 SessionPersistenceSnapshot
记录 { header, revision, sizeBytes? }(header 嵌在 .header 下);更早版本直接返回 header 本身。
插件两种形状都接受。list() 是"尽力而为"的:它遍历整棵会话树,任何一个不可用产物(未来格式、
中断迁移残留的重复 id、编码不匹配)都会让它抛错——此时插件回退到自己的文件系统扫描,只影响该会话,不会让整个功能失效。
- zstd 日志是拼接多帧容器:帧 1 = 恰好一行 header(以换行结尾),帧 2..N = 每次追加的事件批次; DSH 读取器要求第一帧独立解码后恰好是这一行 header。
- 迁移时对 zstd 日志做帧保留手术:只解码帧 1 → 改写 header 的 cwd → 重编码为单帧(带 checksum,与 DSH 后端一致)→ 与其余原始帧(逐字节不变)拼接。绝不能把整个日志压成单帧(会破坏 DSH 读取器的"第一帧=仅 header"不变量)。

文件

dsh-workspace-drag/
├── package.json # dsh.bundle.patch + client inject
├── cordis.patch.yml # 向 web profile 注册插件行 ├── lib/ │ ├── index.js # 宿主端:config/move 两个 HTTP 路由 + 迁移逻辑 │ └── client.js # 浏览器端:设置页(开关) + document 级拖拽引擎 ├── test/ │ ├── fixtures/multiframe-session.jsonl.zstd # 多帧 zstd 会话样本(7 帧) │ ├── verify-core.mjs # zstd 往返 + DSH 帧扫描器兼容校验 │ └── integration-move.mjs # moveSessionToWorkspace 端到端集成测试(含帧数保持断言) └── README.md

宿主端 HTTP 接口

| 方法 | 路径 | 说明 |
| GET | /api/dsh-workspace-drag/config | 读开关 { "enabled": true } |
| POST | /api/dsh-workspace-drag/config | 写开关 { "enabled": false } |
| POST | /api/dsh-workspace-drag/move | { "sessionId", "targetWorkspaceId", "waitMs" } 迁移对话;waitMs(0–30000,可选)让宿主端等待 agent 结束/日志静止后自动完成,失败响应带 code(agent-running / writing / move-failed) |

配置持久化在 ~/.dsh/dsh-workspace-drag.json。

依赖

- 宿主端需要 zstd CLI。插件自动通过 PATH 查找,找不到再 fallback 到常见路径(/opt/homebrew/bin/zstd、/usr/local/bin/zstd、/usr/bin/zstd)。macOS 通过 brew install zstd 安装,Linux 通过 apt install zstd 安装。
- 需要 DSH 内置服务:webServer / sessions / sessionPersistence / workspaceRegistry (@deepseek-ai/dsh-web-app 已全部加载)。
- DSH 版本兼容:peerDependencies 声明为 >=0.0.1-rc.1 中文 · English
预览分享卡片长什么样 ↓lanscer/dsh-workspace-drag
分享 · DeepSeek Harness Hub
lanscer/dsh-workspace-drag

DSH Web UI 插件——把会话拖到任意工作区就能整理

这是你的仓库?认领条目

回到顶部