集中管理会话,支持归档、回收站与自动续跑
30.8/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/30 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add EIGHTfs/dsh-session-conductor该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · other
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 1 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件发起外部网络请求
查看扫描证据(共 122 处,展示前 107 条)
- 删除本地文件递归lib/features/session-ops.js:157
await rm(sessionDir, { recursive: true, force: true }); - 删除本地文件递归lib/features/session-ops.js:161
if ((await readdir(projectDir)).length === 0) await rm(projectDir, { recursive: true, force: true }); - 读取本地文件lib/features/session-ops.js:161
if ((await readdir(projectDir)).length === 0) await rm(projectDir, { recursive: true, force: true }); - 读取本地文件lib/features/session-ops.js:323
text = await decodeAllFrames(readFileSync(filePath)); - 写入本地文件lib/features/session-ops.js:388
mkdirSync(backupDir, { recursive: true }); - 写入本地文件lib/features/session-ops.js:390
copyFileSync(filePath, bak); - 读取本地文件lib/core/config.js:86
try { if (statSync(ws).isDirectory()) return ws; } catch { } - 读取本地文件lib/core/config.js:120
const parsed = JSON.parse(await readFile(file, "utf8")); - 写入本地文件lib/core/config.js:147
await mkdir(path.dirname(file), { recursive: true }); - 写入本地文件lib/core/config.js:150
await writeFile(tmpPath, JSON.stringify({ - 写入本地文件lib/core/config.js:155
await rename(tmpPath, file); - 读取本地文件lib/sessions/events.js:143
for (const group of readdirSync(root)) { - 读取本地文件lib/sessions/events.js:145
if (!existsSync(dir)) continue; - 读取本地文件lib/sessions/events.js:178
const buf = await readFile(file); - 读取本地文件lib/sessions/events.js:280
const buf = await readFile(file); - 写入本地文件lib/shared/atomic-file.js:21
writeFileSync(tmpPath, data); - 写入本地文件lib/shared/atomic-file.js:23
chmodSync(tmpPath, statSync(targetPath).mode); - 读取本地文件lib/shared/atomic-file.js:23
chmodSync(tmpPath, statSync(targetPath).mode); - 写入本地文件lib/shared/atomic-file.js:27
renameSync(tmpPath, targetPath); - 读取本地文件lib/shared/atomic-file.js:36
if (!existsSync(backupPath)) copyFileSync(srcPath, backupPath); - 写入本地文件lib/shared/atomic-file.js:36
if (!existsSync(backupPath)) copyFileSync(srcPath, backupPath); - 发起网络请求lib/template-inject.js:113
res = await fetch(raw, { - 读取本地文件lib/template-inject.js:152
if (!existsSync(file)) return ''; - 读取本地文件lib/template-inject.js:153
const text = readFileSync(file, 'utf8'); - 读取本地文件lib/template-inject.js:169
const raw = readFileSync(url, 'utf8'); - 读取本地文件lib/template-inject.js:253
try { st = statSync(full); } catch (error) { - 读取本地文件lib/template-inject.js:258
const content = readFileSync(full, 'utf8'); - 发起网络请求lib/group.js:231
const raw = await fetch(`http://127.0.0.1:${hostPort}/api/session/create`, { - 发起网络请求lib/group.js:268
const prompt = await fetch(`http://127.0.0.1:${hostPort}/api/session.prompt`, { - 读取本地文件lib/features/base-routes.js:29
zh: JSON.parse(readFileSync(new URL("../i18n/zh.json", import.meta.url), "utf8")), - 读取本地文件lib/features/base-routes.js:30
en: JSON.parse(readFileSync(new URL("../i18n/en.json", import.meta.url), "utf8")), - 读取本地文件lib/core/index-store.js:102
if (!existsSync(legacyPath)) continue; - 读取本地文件lib/features/member-model/locate.js:40
for (const group of readdirSync(root)) { - 读取本地文件lib/features/member-model/locate.js:43
names = readdirSync(join(root, group)); - 读取本地文件lib/features/member-model/switch.js:66
text = await decodeAllFrames(await readFile(filePath)); - 写入本地文件lib/features/member-model/switch.js:87
mkdirSync(backupDir, { recursive: true }); - 写入本地文件lib/features/member-model/switch.js:89
copyFileSync(filePath, file); - 写入本地文件lib/features/member-model/switch.js:100
copyFileSync(backup.file, filePath); - 读取本地文件lib/features/member-model/switch.js:125
const buf = await readFile(filePath); - 读取本地文件lib/features/member-model/switch.js:161
buf = await readFile(filePath); - 读取本地文件lib/features/member-model/switch.js:287
freshTail = await readTailEvents(await readFile(filePath), { tailFrames: 3 }); - 读取本地文件lib/features/member-model/switch.js:315
const after = await readTailEvents(await readFile(filePath), { tailFrames: 3 }); - 读取本地文件lib/features/member-model/switch.js:642
const buf = await readFile(file); - 读取本地文件lib/features/member-model/clone-member.js:55
const text = await decodeAllFrames(readFileSync(targetFile)); - 读取本地文件lib/features/member-model/clone-member.js:65
const text = await decodeAllFrames(readFileSync(sourceFile)); - 写入本地文件lib/features/member-model/clone-member.js:128
copyFileSync(targetFile, backup); - 写入本地文件lib/features/member-model/clone-member.js:133
writeFileSync(tmp, encoded, { mode: 0o600 }); - 写入本地文件lib/features/member-model/clone-member.js:134
renameSync(tmp, targetFile); - 读取本地文件lib/features/member-model/clone-member.js:136
return { ok: true, events: sourceEvents.length, backup, size: statSync(targetFile).size }; - 读取本地文件lib/zstd-frames.js:152
const origBuf = readFileSync(path); - 写入本地文件lib/zstd-frames.js:185
mkdirSync(backupDir, { recursive: true }); - 写入本地文件lib/zstd-frames.js:236
mkdirSync(backupDir, { recursive: true }); - 读取本地文件lib/zstd-frames.js:262
if (!sessionsRoot || !existsSync(sessionsRoot)) return { ok: true, corrupt: [], healthy: 0, total: 0, error: 'sessions 目录不存在' }; - 读取本地文件lib/zstd-frames.js:265
for (const proj of readdirSync(sessionsRoot)) { - 读取本地文件lib/zstd-frames.js:267
if (!statSync(pp).isDirectory()) continue; - 读取本地文件lib/zstd-frames.js:268
for (const sess of readdirSync(pp)) { - 读取本地文件lib/zstd-frames.js:273
const r = await validateHeaderFrame(readFileSync(f)); - 读取本地文件lib/sessions/log-stream.js:67
return await streamSessionEvents(await readFile(file), onEvent); - 读取本地文件lib/session-log.js:24
if (existsSync(p)) return p; - 读取本地文件lib/session-log.js:28
const hit = readdirSync(sessionDir) - 读取本地文件lib/sessions/resolve.js:29
try { return (await stat(p)).isDirectory(); } catch { return false; } - 读取本地文件lib/sessions/resolve.js:32
for (const group of await readdir(root)) { - 读取本地文件lib/sessions/resolve.js:35
for (const dir of await readdir(groupPath)) { - 写入本地文件lib/shared/json-store.js:22
mkdirSync(path.dirname(file), { recursive: true }); - 写入本地文件lib/shared/json-store.js:24
writeFileSync(tmpPath, JSON.stringify(data), "utf8"); - 写入本地文件lib/shared/json-store.js:25
renameSync(tmpPath, file); - 写入本地文件lib/shared/json-store.js:30
await mkdir(path.dirname(file), { recursive: true }); - 写入本地文件lib/shared/json-store.js:32
await writeFile(tmpPath, JSON.stringify(data), "utf8"); - 写入本地文件lib/shared/json-store.js:33
await rename(tmpPath, file); - 读取本地文件lib/shared/json-store.js:39
const parsed = JSON.parse(readFileSync(file, "utf8")); - 读取本地文件lib/shared/json-store.js:49
const parsed = JSON.parse(await readFile(file, "utf8")); - 读取本地文件lib/sessions/export-restore.js:97
if (!existsSync(exportDir)) return { entries: [], error: `导出目录不存在:${exportDir}` }; - 读取本地文件lib/sessions/export-restore.js:105
const firstLine = readFileSync(plainPath, 'utf8').split('\n', 1)[0]; - 读取本地文件lib/sessions/export-restore.js:115
if (existsSync(parentPlain)) { - 读取本地文件lib/sessions/export-restore.js:134
if (existsSync(subsDir)) { - 读取本地文件lib/sessions/export-restore.js:135
for (const name of readdirSync(subsDir)) { - 读取本地文件lib/sessions/export-restore.js:137
if (!existsSync(plainPath)) continue; - 写入本地文件lib/sessions/export-restore.js:218
mkdirSync(join(objRoot, hash.slice(0, 2)), { recursive: true, mode: 0o700 }); - 写入本地文件lib/sessions/export-restore.js:219
writeFileSync(target, buf, { mode: 0o600 }); - 删除本地文件lib/sessions/export-restore.js:253
unlinkSync(cacheFile); - 写入本地文件lib/sessions/export-restore.js:338
mkdirSync(entry.targetDir, { recursive: true, mode: 0o700 }); - 写入本地文件lib/sessions/export-restore.js:343
writeFileSync(tmp, encoded.buffer, { mode: 0o600 }); - 写入本地文件lib/sessions/export-restore.js:344
renameSync(tmp, target); - 读取本地文件lib/sessions/member-trace.js:117
const buf = await readFile(file); - 读取本地文件build.cjs:95
src += fs.readFileSync(path.join(partsDir, name), "utf8"); - 读取本地文件build.cjs:103
const cur = fs.existsSync(clientPath) ? fs.readFileSync(clientPath, "utf8") : ""; - 写入本地文件build.cjs:112
fs.writeFileSync(clientPath, src); - 读取本地文件lib/eio-repair.js:42
const size = statSync(filePath).size; - 读取本地文件lib/eio-repair.js:72
if (!sessionsRoot || !existsSync(sessionsRoot)) { - 读取本地文件lib/eio-repair.js:77
for (const proj of readdirSync(sessionsRoot)) { - 读取本地文件lib/eio-repair.js:79
if (!statSync(pp).isDirectory()) continue; - 读取本地文件lib/eio-repair.js:80
for (const sess of readdirSync(pp)) { - 写入本地文件lib/eio-repair.js:126
mkdirSync(bk, { recursive: true }); - 写入本地文件lib/eio-repair.js:129
copyFileSync(filePath, backup, fs.constants.COPYFILE_EXCL); - 写入本地文件lib/eio-repair.js:157
renameSync(eioTmpPath, filePath); - 读取本地文件lib/repair.js:306
try { return existsSync(sessionsRootOf()); } catch { return false; } - 读取本地文件lib/repair.js:377
if (!root || !existsSync(root)) return { ...report, error: `sessions 目录不存在: ${root}` }; - 读取本地文件lib/repair.js:378
for (const proj of readdirSync(root)) { - 读取本地文件lib/repair.js:381
try { st = statSync(projectDir); } catch { continue; } - 读取本地文件lib/repair.js:384
try { sessions = readdirSync(projectDir); } catch { continue; } - 读取本地文件lib/repair.js:388
try { sst = statSync(sessionDir); } catch { continue; } - 写入本地文件lib/repair.js:429
mkdirSync(backupDir, { recursive: true }); - 写入本地文件lib/repair.js:445
renameSync(join(entry.dir, "session.jsonl"), target); - 读取本地文件lib/seq-gap-repair.js:27
const orig = await readFile(path); - 写入本地文件lib/seq-gap-repair.js:188
mkdirSync(bakDir, { recursive: true }); - 写入本地文件lib/seq-gap-repair.js:190
writeFileSync(bakPath, orig); - 读取本地文件lib/sessions/tail-io.js:100
buf = await readFile(filePath);
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 会话功能增强插件(重命名/分支/归档)
README
由 DeepSeek 最新模型翻译生成dsh-session-conductor
DSH 会话管理增强插件:面板管理会话、批量删除与回收站、损坏修复、自动续跑、模板注入,以及成员(子代理)的模型/权限/换名管理。
功能
| 功能 | 做什么 | 入口 |
| 会话管理面板 | 五视图(全部/已归档/活跃/回收站/说明);归档、删除、撤回、置不活跃、释放空闲 | 侧边栏「会话管理」 |
| 回收站 | 删除只打标记,可单条/多选/按批次还原;到期或一键清空才真删盘 | 面板「回收站」 |
| 自动重命名 | 回合后分析内容,主题偏离时生成新标题 | 面板逐会话开关 |
| 自动续跑 | 识别非人为中断并继续原任务,失败 30s 重试 | 面板逐会话开关 |
| 会话分组 | 按工作区分组显示;分组下新建会话 | 设置 → 插件 → 会话分组 |
| 撤回最后一条消息 | 删除最后一条用户消息及整轮回复(预览 + 二次确认 + 备份) | 面板按钮 |
| 损坏修复 | seq-gap / EIO 坏块 / 双格式 / zstd 帧级损坏 四类 | 面板「说明」页 + /repair 系列 |
| 价值分析 | LLM 给会话分类(已完成/未完成/久未活跃/活跃中) | 面板按钮 |
| 全文搜索 | FTS5 优先,内置 zstd 扫描兜底 | 面板搜索框 |
展开完整文档(README 剩余 1 节)
dsh-session-conductor
DSH 会话管理增强插件:面板管理会话、批量删除与回收站、损坏修复、自动续跑、模板注入,以及成员(子代理)的模型/权限/换名管理。
功能
| 功能 | 做什么 | 入口 |
| 会话管理面板 | 五视图(全部/已归档/活跃/回收站/说明);归档、删除、撤回、置不活跃、释放空闲 | 侧边栏「会话管理」 |
| 回收站 | 删除只打标记,可单条/多选/按批次还原;到期或一键清空才真删盘 | 面板「回收站」 |
| 自动重命名 | 回合后分析内容,主题偏离时生成新标题 | 面板逐会话开关 |
| 自动续跑 | 识别非人为中断并继续原任务,失败 30s 重试 | 面板逐会话开关 |
| 会话分组 | 按工作区分组显示;分组下新建会话 | 设置 → 插件 → 会话分组 |
| 撤回最后一条消息 | 删除最后一条用户消息及整轮回复(预览 + 二次确认 + 备份) | 面板按钮 |
| 损坏修复 | seq-gap / EIO 坏块 / 双格式 / zstd 帧级损坏 四类 | 面板「说明」页 + /repair 系列 |
| 价值分析 | LLM 给会话分类(已完成/未完成/久未活跃/活跃中) | 面板按钮 |
| 全文搜索 | FTS5 优先,内置 zstd 扫描兜底 | 面板搜索框 |
| 压缩模型 | 上下文自动压缩使用独立模型 | 设置 → 插件 → 压缩模型 |
| 模板注入 | 方案/收尾模板;本地文件、在线网址、目录浏览三种导入 | 设置 → 会话管理 |
| 自动重命名模型 | 指定标题分析用的模型 | 设置 → 会话管理 |
| 成员模型切换 | 切单个或全部成员的模型,可跟随主代理 | /model-switch、set_member_model |
| 成员权限预设 | 查看/切换成员权限预设,支持批量与跟随 | /perm-switch、set_member_permission |
| 成员换名 | 新建成员并把原会话内容搬进去 | clone_member_as |
| 创建成员并选模型 | 创建时即指定模型,首轮就用它 | create_teammate_with_model |
| 指定模型新建会话 | 新建会话并直接指定 provider/model | create_session |
| 记忆取回 | 上下文用量骤降时自动回注最近几轮对话 | 自动注入 + recall_memory |
| 上下文用量 | 查自己会话的占用与构成 | context_usage |
| 跨会话消息 | 给另一个会话发消息,空闲时自动唤醒 | list_sessions、send_to_session |
| 成员轨迹 | 读子代理的完整执行过程:思考、正文、工具调用与结果 | read_member_trace |
环境要求
| 项 | 要求 |
| DSH | 0.2.1 及以上(更早版本功能可用,但列表缓存不生效,会话多时列表构建变慢) |
| Node | 与宿主自带的 Node 一致 |
| 平台 | Linux(群晖 DSM / fnOS 等);纯 Node 实现,无原生依赖 |
用法
面板与设置页
- 面板:侧边栏底部「会话管理」展开。五个视图分别是全部、已归档、活跃、回收站、说明。
行内可归档、删除、撤回最后一条消息、开关自动重命名/自动续跑;顶部可搜索、价值分析、释放全部空闲。
- 设置页:左侧栏「会话管理」独立页。模板注入(方案/收尾两个槽位,可上传本地 md、填在线网址、浏览 DSH 目录导入,导入后可再编辑)与自动重命名模型选择。
聊天框指令
/model-switch —— 查看/切换成员模型:
/model-switch # 无参:列出成员与各自模型 /model-switch writer # 只给成员:查它实际在用的模型 /model-switch writer sa6400/deepseek-v4.1-flash # 成员 + 模型:切换 /model-switch * auto # 成员写 * = 全部;模型写 auto = 跟随我
/perm-switch —— 查看/切换成员权限预设:
/perm-switch # 无参:列出成员与各自预设 /perm-switch writer # 只给成员:查 preset / sandbox / approval /perm-switch writer danger-full-access # 成员 + 预设:切换 /perm-switch * auto # 成员写 * = 全部;预设写 auto = 跟随我
两条指令都支持:成员位置可填成员名、唯一子串或 sessionId; 表示全部成员(不含自己); auto 表示跟随主代理当前值。切换后回执会带上「实际生效」的查证结果。
AI 工具
list_models({}) // 列出可用 provider 与模型 id
set_member_model({ target, provider, model }) // 三者都可空:target 空=全部成员;provider/model 空=跟随我
set_member_permission({ target, preset }) // 两者都可空:target 空=全部成员;preset 空=跟随我
list_permission_presets({}) // 列出可选权限预设
clone_member_as({ source, name, description, withHistory, provider, model, subagentProvider })
// source/name 必填;withHistory 默认 true(false=只建空成员)
create_teammate_with_model({ name, description, prompt, provider, model, subagentProvider, context })
// name/description/prompt/provider/model 必填
create_session({ cwd, workspaceId, provider, model, text, dryRun, sessionId })
// 全可空:cwd 缺省=调用方 cwd;dryRun=true 只预览
list_sessions({ query, limit, offset, fromIndex }) // 全可空:fromIndex=true 直接读索引(秒回)
send_to_session({ sessionId, text, mode, dryRun }) // sessionId/text 必填;mode=queue|steer
recall_memory({ rounds, session }) // 都可空:rounds 默认取配置、上限 50;session 空=自己
context_usage({}) // 无参
read_member_trace({ session, rounds, detail, include, maxCharsPerItem })
// session 空=自己(可填成员名/id/前缀/标题);rounds 默认 1(上限 20) // detail=summary(每条一行)|full(完整文本);include 可裁 reasoning,text,tool // maxCharsPerItem 单条截断(默认 800)
典型调用:
// 全部子代理都换成我现在用的模型
set_member_model({})
// 只把 writer 切到指定模型
set_member_model({ target: "writer", provider: "sa6400", model: "cn:deepseek-v4.1-flash" })
// 把 probe1 克隆成 rename1(换名用)
clone_member_as({ source: "probe1", name: "rename1" })
// 给另一个会话发消息(dryRun 先预览目标状态与限流余量)
send_to_session({ sessionId: "session-xxxx", text: "继续刚才的任务", dryRun: true })
// 看子代理最近一轮的执行过程(子代理只有最后一条回复会被自动发回,中间的思考靠这里读)
read_member_trace({ session: "writer" })
// 看最近 3 轮,只要思考与工具调用
read_member_trace({ session: "writer", rounds: 3, include: "reasoning,tool" })
// 要完整文本(默认 summary 每条压成一行)
read_member_trace({ session: "writer", detail: "full" })
API
插件以 /api/session-conductor/ 前缀注册宿主路由:
| 端点 | 方法 | 用途 |
| /list | GET | 会话列表;?fromIndex=true 读落盘索引秒回,?job=1 交给后台 job |
| /archive /restore | POST | 归档 / 恢复会话 |
| /delete | POST | 删除会话(拒绝运行中) |
| /undo | POST | 撤回最后一条消息 |
| /auto-rename /auto-continue | POST | 两个逐会话开关 |
| /auto-continue-gate | GET/POST | 全局续跑闸门 |
| /release | POST | 释放空闲会话 |
| /value-analysis | POST | 价值分析 |
| /repair /repair-eio /repair-dual | POST | 三类损坏修复 |
| /search | GET | 全文搜索 |
| /compaction-model /auto-rename-model | GET/POST | 两个模型设置 |
| /templates /templates/dir | GET/POST | 模板注入与目录浏览 |
| /i18n | GET | 语言包(zh/en) |
curl http://<host>/api/session-conductor/list
→ { "ok": true, "sessions": [ { "id": "...", "title": "...", "cwd": "...", "updatedAt": 172... } ], "total": N }
curl -X POST http://<host>/api/session-conductor/archive \
-H "Content-Type: application/json" -d '{"id":"<sessionId>"}'
→ { "ok": true, "archived": true }
文档索引
- 文件目录结构 — 目录树与文件作用
- 版本列表 — 按 git 提交聚合的版本记录
- 函数列表 — lib/ 导出函数的名称/位置/签名
- 模型与权限切换机制 — 子代理切换的实现依据与内部机制预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
EIGHTfs/dsh-session-conductor
集中管理会话,支持归档、回收站与自动续跑
相关插件 · 其他
模型破甲清洗YuJunZhiXue/dsh-purge
⚔️ DeepSeek Harness 网络安全红队工具dsh-purge
★ 14,822已汉化DeepSeek 客户端
73
逆向分析桥接Fanqi89/dsh-rea
REA(Reverse Engineer Anything)MCP 桥接,用来把 REA 逆向工具接入 DSH 插件
★ 51已汉化DSH
72
红队越狱测试套件Minglink/dsh-infinite-gen-5
DeepSeek v4.1 flash 逆向工具无限五代 求 Star 收藏 ⭐欢迎大家提交项目的改进
★ 3,759已汉化DSH
71.4
语音女友beiyege-01/dsh-voice-ai-girlfriend
语音 AI 女友Voice AI girlfriend for DeepSeek Harness:Whisper…
★ 718已汉化DSH
71.2
协同办公空间dream-num/univer-workspace
一个让人类与 AI Agent 共同创作、协作和审阅的开源 Office 工作空间。
★ 2,261已汉化DSH
70.7
破甲评测WoYun520/dsh-purge
在本机分离宿主拦截与模型拒绝,做受控红队评测
★ 199已汉化DSH
69.7