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

工作区文件夹 ayachinene285/dsh-session-move

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

DeepSeek Harness 插件:侧栏工作区文件夹分组与会话移动 · Workspace folders and…

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add ayachinene285/dsh-session-move
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
dsh 原生插件 · browser
装得上吗
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 13 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

读写/删除本地文件发起外部网络请求
查看扫描证据(共 32 处,展示前 25 条)
  • 发起网络请求
    lib/client.js:107
    const response = await fetch(API + "?view=folders", { headers: { accept: "application/json" } });
  • 发起网络请求
    lib/client.js:113
    const response = await fetch(API, {
  • 发起网络请求
    lib/client.js:394
    fetch(API + "?sessionId=" + encodeURIComponent(sessionId), { headers: { accept: "application/json" } })
  • 发起网络请求
    lib/client.js:437
    fetch(API, {
  • 发起网络请求
    lib/client.js:460
    fetch(API, {
  • 读取本地文件
    lib/engine.js:187
    workspace.missing = (await fsp.stat(workspace.path)).isDirectory() !== true;
  • 读取本地文件
    lib/engine.js:209
    const existed = await fsp.stat(raw).then((value) => value.isDirectory(), () => false);
  • 写入本地文件
    lib/engine.js:210
    if (!existed) await fsp.mkdir(raw, { recursive: true });
  • 读取本地文件
    lib/engine.js:211
    const canonical = await fsp.realpath(raw).catch(() => {
  • 读取本地文件
    lib/engine.js:295
    const stat = await fsp.stat(target).catch(() => undefined);
  • 写入本地文件
    lib/engine.js:304
    await fsp.mkdir(target, { recursive: true });
  • 读取本地文件
    lib/engine.js:305
    const after = await fsp.stat(target).catch(() => undefined);
  • 读取本地文件
    lib/engine.js:321
    const real = await fsp.realpath(cwd).catch(() => undefined);
  • 删除本地文件
    lib/engine.js:389
    await fsp.rm(file, { force: true });
  • 写入本地文件
    lib/engine.js:392
    await fsp.mkdir(dirname(file), { recursive: true });
  • 写入本地文件
    lib/engine.js:393
    await fsp.writeFile(file, JSON.stringify({ version: 1, items }, null, 2) + "\n", "utf8");
  • 写入本地文件
    lib/engine.js:495
    await fsp.mkdir(moved.fromDir, { recursive: true });
  • 写入本地文件
    lib/engine.js:496
    await fsp.writeFile(moved.fromFile, moved.original);
  • 删除本地文件
    lib/engine.js:497
    await fsp.rm(moved.toFile, { force: true });
  • 删除本地文件
    lib/engine.js:498
    await fsp.rmdir(moved.toDir).catch(() => {});
  • 删除本地文件
    lib/engine.js:575
    await fsp.rm(fromFile);
  • 删除本地文件
    lib/engine.js:576
    await fsp.rmdir(fromDir).catch(() => {});
  • 读取本地文件
    lib/folders.js:81
    return normalize(JSON.parse(await fsp.readFile(storeFile(persistence), "utf8")));
  • 写入本地文件
    lib/folders.js:89
    await fsp.mkdir(dirname(file), { recursive: true });
  • 写入本地文件
    lib/folders.js:90
    await fsp.writeFile(file, JSON.stringify(state, null, 2) + "\n", "utf8");
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
dsh-session-move DSH 的侧栏只有「工作区(目录)」这一层,也没有把会话挪到别的工作区的接口。这个插件补了这两块: - 在工作区上面加一层文件夹。纯虚拟的,能嵌套,能放多个工作区,磁盘上不建任何目录; - 会话可以在工作区之间搬,搬完以后这条会话里跑的东西都在新目录下。 代码分两块。lib/index.js 跑在 DSH 的本地服务进程里,负责读会话文件、改 cwd、开一个本地接口;lib/client.js 是网页里的部分,负责侧栏、菜单和弹窗。 安装 1. clone 或者下载这个仓库到任意目录; 2. 装进 profile:dsh plugin --profile <profile 名> add <插件目录>。桌面版的 profile 由应用自己管理,命令被拒的话,在「插件」页里装,或者手动把 dsh-session-move 加到 profile 的 package.json 里 dsh.profile.bundles 下; 3. 完全退出 DSH 再打开。改插件不是刷新页面就能生效,界面和后台都要重新加载。 用法 会话行右边的「…」里有「移动到工作区 / 文件夹…
展开完整文档(README 剩余 1 节)
dsh-session-move

DSH 的侧栏只有「工作区(目录)」这一层,也没有把会话挪到别的工作区的接口。这个插件补了这两块:

- 在工作区上面加一层文件夹。纯虚拟的,能嵌套,能放多个工作区,磁盘上不建任何目录;
- 会话可以在工作区之间搬,搬完以后这条会话里跑的东西都在新目录下。

代码分两块。lib/index.js 跑在 DSH 的本地服务进程里,负责读会话文件、改 cwd、开一个本地接口;lib/client.js 是网页里的部分,负责侧栏、菜单和弹窗。

安装

1. clone 或者下载这个仓库到任意目录;
2. 装进 profile:dsh plugin --profile <profile 名> add <插件目录>。桌面版的 profile 由应用自己管理,命令被拒的话,在「插件」页里装,或者手动把 dsh-session-move 加到 profile 的 package.json 里 dsh.profile.bundles 下;
3. 完全退出 DSH 再打开。改插件不是刷新页面就能生效,界面和后台都要重新加载。

用法

会话行右边的「…」里有「移动到工作区 / 文件夹…」,弹窗里选目标:

- 选工作区:真的搬过去,会话的工作目录会改成那个目录;
- 在文件夹那一行点「把会话放这里」:只在侧栏归组,工作目录不动;
- 会话已经在某个文件夹里时,弹窗最上面多一行「移出文件夹」,点它回到工作区下面;
- 也可以直接填一个新目录,插件会把它登记成新工作区。

同一条会话可以反复搬。已经在目标工作区、会话正在跑、子代理会话,这几种情况会直接给提示,不会动数据。目标目录不存在时,默认先按同名建一个空目录再搬,弹窗里可以把这个行为关掉。

文件夹分组

侧栏右上角「+」可以新建文件夹,不用选本地目录。文件夹能装文件夹,也能装任意多个工作区;工作区本身不能当父级。

工作区行的「…」里有「移入文件夹…」和「不放入文件夹(顶层)」。文件夹行的「…」里有新建子文件夹、重命名、移入其它文件夹、删除。删除只是解散这个文件夹,里面的东西上移一层。

「+」→「新增工作区(选择本地目录)」还是官方的选目录流程;文件夹的「…」里也有「新建工作区(选目录后放进这里)」,建完自动放进去。

展开状态记在浏览器 localStorage 里,默认展开,点行首的箭头收放。

会话可见性跟官方一致:已归档的会话默认隐藏(工作区「…」→「显示已归档的会话」可以切,这个开关跟官方和归档管理插件共用一份状态),子代理会话不显示,不是当前会话的空会话不显示。没归进任何工作区的会话放在最后「未分组」里。

会话也能直接放进文件夹,只动侧栏分组:会话「…」→ 移动到工作区 / 文件夹… → 在文件夹那一行点「把会话放这里」。放进去之后它只在文件夹下面出现一次,不会再重复出现在所属工作区里;想放回去用「移出文件夹」。

会话移动是怎么做的

DSH 判断一条会话属于哪个工作区,看的是会话自己记录的工作目录:

- 挂载会话的时候,DSH 拿会话文件里的 cwd 跟工作区路径比对,不一致就拒绝;
- 会话文件在磁盘上的位置也由这个 cwd 推出来,位置和记录对不上会被当成坏会话;
- 官方没有提供移动会话的接口。

所以插件分两步做完:

1. 改数据:重写会话文件第一个 zstd 帧里记录的 cwd,把会话目录搬到新 cwd 对应的项目目录下,正文逐字节不动。写完马上自检,失败就回滚。
2. 重新挂载:让 DSH 按磁盘现状重新读一遍这条会话,挂到目标工作区,从旧工作区摘掉,然后马上放掉,不长期占内存。

移动完不需要重启 DSH,也不用手工改 workspace.json,归属由 DSH 自己写。

冷会话和打开着的会话

一条会话只要被打开过(在对话页看过、聊过),DSH 的进程就会一直留着它,并且握着会话文件的写入权,官方没有关掉它的接口。所以:

- 没打开过的:点一下就好,不用重启;
- 打开着但空闲的:这时候改不了文件,插件把这次移动记成待办,下次 DSH 启动时(那时会话都是冷的)自动做完。待办存在 <DSH 数据目录>/storages/session-move-pending.json。重放失败不会把记录删掉,失败原因写进 lastError,下次启动继续试,弹窗顶上也会显示上次为什么没成;
- 有回合在跑的:直接拒绝,等它跑完再搬。

工作区目录不存在时

工作区的目录如果在 DSH 外面被删了或者改了名,DSH 就解析不出会话记录的 cwd,会话会在侧栏掉进「未分组」,工作区的会话数变成 0,往那里搬也只会得到一句「目标目录不存在」。

现在弹窗会把它标出来(行尾写「目录不存在」,选中后下面显示完整路径),并且默认直接修:

- 点「移动」就行,插件先按同名把空目录建出来,再搬会话,然后把归属补上。补归属的时候会顺手让 DSH 重新解析一次 cwd,所以不用重启就能在侧栏看到;
- 不想让它建目录,把弹窗里的「目录不存在时自动新建同名目录」取消掉,那样会直接报错;
- 如果目录只是改了名,别让它建空目录,用下面的「移动到新目录」填真正的路径,会自动登记成新工作区。

重启后重放的待办也按「目录不在就先建」处理。

本地接口

后台只加了一个本地接口,不替换官方任何东西:

| 方法 | 路径 | 说明 |
| GET | /api/dsh-session-move?sessionId=<id> | 工作区列表、这条会话的归属、它的待办移动 |
| POST | /api/dsh-session-move | { action: "move", sessionId, workspaceId 或 targetPath, title?, createMissingDir? } |

写请求只接受本机同源调用,会校验 Origin、Host 和 Sec-Fetch-Site。

配置

package.json 的 dsh.client 指向界面部分的入口,cordis.patch.yml 只有一条 insert,不禁用官方任何入口。

- insert:
- id: dsh-session-move
name: 'dsh-session-move'

开发时踩过的坑

- 改了界面部分也要完整重启 DSH。DSH 会给每个界面模块按文件内容算一个版本号,并且按 immutable 缓存;只刷新页面的话,页面会拿着旧的版本号去取,被后台拒掉,表现可能是「插件加载失败」,严重的时候应用起不来。
- 不要直接读没声明依赖的 ctx.xxx。Cordis 里访问没声明的服务属性会直接抛异常,取可选服务用 ctx.get("xxx")。
- 注册类调用都要自带 try/catch,包括路由、快捷键、槽位注册。界面部分初始化时抛错,DSH 会判定 entry did not activate,弹启动失败并提示禁用第三方插件。
- 同理,插件对外注册的地方都做了兜底,最坏情况只是这个功能不可用,不会连累 DSH 启动。

已知边界

- 移动会改会话的工作目录,之后这条会话里的工具调用都在新目录下跑;历史记录里的旧路径不会改写。
- 有回合在跑的会话不能移动。
- 只处理官方的 JSONL 存储(session-persistence-jsonl,日志格式 v4),别的后端会因为没有 locate() 被拒。
- 已经归档的会话也能移动(归档集合按 id 全局存),但它在侧栏里还是显示为归档。
- 恢复会话时 DSH 会追加一条 session/end-seed 事件,这是官方的恢复标记,不影响历史内容。

卸载

从 profile 的 dsh.profile.bundles 里删掉 dsh-session-move,执行 dsh plugin --profile <name> remove dsh-session-move,然后完整重启 DSH。
预览分享卡片长什么样 ↓ayachinene285/dsh-session-move
分享 · DeepSeek Harness Hub
ayachinene285/dsh-session-move

DeepSeek Harness 插件:侧栏工作区文件夹分组与会话移动 · Workspace folders and…

这是你的仓库?认领条目

回到顶部