dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
隔离舱:在 DSH 主会话之外运行受沙箱约束的隔离任务;主会话默认完全无感,结果返回与文件导出都要手动确认。
在 DSH 主会话之外运行受沙箱约束的隔离任务。主会话默认完全无感:不写入消息、不进入 模型上下文、界面消息流里没有任何自动痕迹;结果返回与文件导出都必须由用户手动确认。
简体中文 | English
| 项目 | 内容 |
|---|---|
| 当前版本 | v0.2.0(Host build: 2) |
| 侧车协议 / 数据库 schema | 1 / 1 |
| 支持宿主 | DSH 0.2.1+(桌面版 0.2.1-rc.2 验证;0.1.7 不支持,v0.1.3 是 0.1.x 最后版本) |
| 形态 | Rust 侧车(isolation-pod-core)+ JS Host 薄壳 + 官方会话界面 Client |
| 依赖 | 无运行期 npm 依赖;侧车静态链接 SQLite |
| 平台 | Windows x64 已本机验证;Linux x64 / macOS x64+arm64 由 CI 构建(未做本机面板验收) |
| 许可 | MIT,见 LICENSE |
| 文档 | 读者 | 内容 |
|---|---|---|
README.md(本文) | 使用者、二次开发者 | 特性、原理、安装、使用、配置、API、数据、限制、开发 |
README.en.md | English readers | 本文的英文版本 |
使用教程.md | 第一次上手 | 按操作顺序的分步走查、排障、验收清单 |
需求说明.md | 需求/验收方 | 功能需求基线(冻结,不随实现修订) |
CHANGELOG.md | 所有人 | 版本变更记录(Keep a Changelog) |
docs/ARCHITECTURE.md | 维护者 | 分层、进程边界、状态所有权、设计决策 |
docs/PROTOCOL.md | 维护者 | 侧车/Host/Client 字段级契约 |
docs/MIGRATION.md | 升级用户 | v0.1.3 → v0.2.0 迁移、回滚、FAQ |
NOTICE.md | 合规 | 第三方依赖与许可 |
uiWorkspace.openSession 进入 DSH 官方会话面板,直接展示
官方消息流、工具卡片、思考过程与输入框;隔离舱不自绘转写。sandbox/mode=workspace-write;沙箱外写入由
DSH 文件沙箱硬拒绝,不依赖提示词自觉。首轮模型轮次之前还有一次越界写探针。tools.guard 强制;preset 缺失不会清空白名单。/status、诊断页、核心重启、stderr 环形日志、协议/schema 版本校验。Client(React 面板 / 任务操作条 / 恢复卡)
│ /isolation-pod/api(激活期令牌)
JS Host 薄壳(Cordis 插件)
├─ 通过 stdio NDJSON 调用 Rust 侧车
└─ 调用 DSH services:agents / sessions / sessionQuery / sandboxPolicy / fs / presets
Rust 侧车(SQLite / 队列 / 沙箱路径 / 文件 / 导出 / 迁移)
打开任务时,Client 调 Host 的 openTask,然后 ctx.uiWorkspace.openSession(sessionId) 切到
官方 conversation 主面板。任务会话的完整记录由 DSH 会话日志渲染;隔离舱只保存状态摘要、
审计与导出记录。
详细架构见 docs/ARCHITECTURE.md,协议见
docs/PROTOCOL.md。
<sandboxRoot>/<subdir?>/<taskId>,占用并发槽或入队;sandbox/mode、
approval/policy=never、挂载 preset、安装工具 guard、注入系统提示段;task.markRunning 之后执行越界写探针;探针通过后,发送一条干净的 任务:<描述> 用户消息;dsh web;本地使用 0.2.1-rc.2 桌面版验证)。webServer 时插件不会激活。lib/bin/win32-x64/isolation-pod-core.exe;ISOLATION_POD_CORE_BIN 指向自定义侧车路径。dsh-isolation-pod bundle 已选中、插件行启用;lib/index.js)被替换后 Node 会
按 URL 缓存旧模块,必须重启;只有 Client 半更新可以热重载。在 <DSH_HOME>\profiles\<profile>\cordis.patch.yml 末尾追加:
- insert:
- id: dsh-isolation-pod
name: '<仓库绝对路径>\lib\index.js'
保存后宿主重新应用 profile;Host 半有改动时仍需重启。不要与 bundle 安装同时启用: 虽然 Host 的重复激活保护会忽略第二个实例,但可能出现重复的 Client 入口与配置混淆。 切换时只保留一种方式。
curl.exe -s http://127.0.0.1:<port>/isolation-pod/status
应看到 pluginVersion: "0.2.0"、coreVersion: "0.2.0"、protocol: 1、schemaVersion: 1、
coreStatus: "ready"、build: 2。侧边栏出现「隔离舱」入口。
git pull && pnpm install && pnpm run build;
Host 改动后重启 DSH。docs/MIGRATION.md §5;注意新版数据只在
pod.db 中,旧版不读取。pod.db;停机后可只读检查。E:\pod-work),
或点「选择目录」;保存。cleanup 另有
record 范围;任务面板不提供单独的「只删记录」按钮)。完整分步走查见 使用教程.md。
| 页签 | 内容 |
|---|---|
| 任务 | 搜索/筛选(全部、进行中、已结束、失败类);任务行含状态、轮数、目录、在线/排队信息;操作:打开会话、详情面板、文件、停止/恢复、清理;支持批量清理终态任务。 |
| 新建 | 任务描述、可选沙箱子目录、主会话选择;显示沙箱/预设/队列提示。 |
| 配置 | 沙箱根、允许写入、工具白名单、超时/并发/队列、导出、preset、预览/探针/自动恢复/日志级别。 |
| 导出记录 | 每次导出的目标、方式、冲突策略、逐项状态;复制模式可用「撤销」。 |
| 诊断 | 核心/Host/协议/schema 信息、DB/二进制路径、stderr/诊断尾部、兼容性探测、「重启隔离舱核心」。 |
conversation.input.dock,id isolation-pod-task):
状态 chip、面板、文件、返回、导出、停止按钮,以及 Fork 警示。conversation.session.header.utilities,id isolation-pod):
打开隔离舱面板。conversation.composer chain,priority −5):
当任务会话不是 live 时接管输入框,显示只读说明与「恢复隔离会话」;恢复前不会把消息
发给未隔离的 Agent。live 会话使用官方输入框,不替换。mainSessionId;新建任务的主会话选择使用
用户主会话列表(排除 pod 任务会话与 subagent 会话)。| 状态 | 含义 |
|---|---|
queued | 已创建,等待并发槽位 |
starting | 已占槽,正在创建 Agent/setup |
running | 已进入运行态(首轮前先做沙箱自检,随后才开始模型轮次) |
completed | 最后一轮正常完成(max-tokens 与 forked 也按完成结算) |
failed | 创建/执行/工具错误或 blocked |
timeout | 超过每轮时限 |
cancelled | 用户停止或取消 |
interrupted | 宿主重启/进程消失;历史仍可查看,可恢复 |
maxConcurrent 统计 starting+running;超限且 queueEnabled=true 时进入 FIFO 队列,
显示排队位置;一个任务结束/取消后自动派发下一个。queueEnabled=false 时,超限且没有已有排队任务会直接返回「忙碌」;如果队列里仍有任务,
新任务会继续排在队尾(切换开关后建议先处理已有队列)。queued/starting/running 都会标记 interrupted,不会自动重放。timeoutMs 是每轮超时(30 秒–2 小时,默认 10 分钟),不是整个任务。deadline.expired,Host 取消 Agent;10 秒结算宽限;Host 另有
timeoutMs+30s 看门狗。autoResumeOnOpen=true(默认):打开任务时若会话不 live,Host 用 task.reattach +
agents.resume 恢复隔离 setup,再打开官方会话;不自动发消息。agent/created 安全网会在首轮前补齐隔离 setup。MAIN_SESSION_NOT_LIVE。allowRememberChoice 只允许预填上次目标路径,仍需每次确认。<targetDir>/.isolation-pod-undo/<exportId>/;撤销在 exportVerify 开启时校验 BLAKE3 哈希
(哈希在导出时总会记录),目标被修改/删除或变成链接时返回冲突。旧版/无哈希记录不会校验,
撤销会直接删除目标,且无法恢复被覆盖的原文件;请先备份。 移动模式在 UI 中不提供撤销。previewBytes 与 previewChars 限制;
二进制文件返回明确提示,不渲染乱码。.. 会被拒绝。maxTasks/maxExports/retentionDays 清理记录(maxTasks/retentionDays 针对终态任务,
maxExports 针对导出记录并会在每次导出后清理;不自动删任务文件)。配置保存在侧车 SQLite 中;面板「配置」修改,或通过 setConfig。默认值/范围:
| 键 | 默认 | 说明 |
|---|---|---|
sandboxRoot | '' | 必填专用绝对目录;空则拒绝任务,绝不自动使用工作区。拒绝文件系统根、用户主目录、DSH_HOME/数据库目录、当前 cwd、SystemRoot/ProgramFiles,也不能包含这些目录 |
allowWrites | true | false 时任务使用 read-only 沙箱模式 |
allowedTools | pwsh, bash, read, write, edit, glob, grep | 白名单上限;至少一个;guard 强制 |
timeoutMs | 600000 | 每轮超时 30 000–7 200 000 ms |
readContext | true | 读取主会话最近 12 条消息作为只读背景 |
maxConcurrent | 3 | 1–8 |
queueEnabled | true | 超限排队;关闭后无既有队列时直接忙碌(已有队列仍接收新任务) |
enableExport | true | 关闭后导出/撤销接口拒绝 |
allowRememberChoice | false | 仅允许预填路径,不构成授权 |
presetId | '' | 挂载的 Agent preset;留空则不挂载(可能没有工具) |
maxTasks / maxExports | 200 / 200 | 1–5000;maxTasks 启动时清理超出的终态任务记录,maxExports 启动时与每次导出后清理超出的导出记录 |
retentionDays | 0 | 0–3650;仅启动时清理终态记录,不删文件 |
previewBytes | 307200 | 单文件预览字节上限 16 KiB–1 MiB(侧车强制) |
previewChars | 20000 | 单次预览字符上限 200–20 000 |
exportVerify | true | 撤销时校验 BLAKE3(导出时总会记录哈希;关闭后撤销不校验) |
sandboxProbeMode | 'strict' | 严格/宽松自检;见下 |
autoResumeOnOpen | true | 打开任务时尝试恢复会话 |
logLevel | 'info' | trace/debug/info/warn/error/off;UI 提供 error/warn/info/debug,API 接受全部六个 |
sandboxProbeMode 语义:
ambiguous/failed):strict 失败,warn 记录警告后继续;skipped-no-parent 通过并警告。Host 注册前缀 /isolation-pod:
| 路由 | 认证 | 用途 |
|---|---|---|
GET /isolation-pod/status | 无(本地诊断) | 版本、核心状态、DB/二进制路径、沙箱摘要、compat、诊断;不含完整 token(仅 tokenPrefix 前 8 位) |
GET /isolation-pod/bootstrap | DSH 浏览器认证 | 返回 {ok:true, token};未认证 401 |
POST /isolation-pod/api | x-ipp-token 头 | {method,args};body ≤ 256 KiB |
令牌是每次激活随机 UUID,经索引注入行 __DSH_IPP__ 交付,不落盘;Client 恢复链为
__DSH_IPP__ → bootstrap → 同源 HTML 抓取 → 单次受控重载。失败返回
{ok:false,code,message};403/404/405/413 分别对应 token/路径/方法/请求体。
方法(18 个):
| 方法 | 参数 | 说明 |
|---|---|---|
getState | {mainSessionId?} | 全量面板状态(config/tasks/exports/core/sandbox/compat) |
setConfig | {patch} | 校验/保存配置,返回 messages |
startTask | {mainSessionId, description, subdir?, label?} | 新建任务;可能排队 |
openTask | {taskId} | 打开/自动恢复任务会话 |
resumeTask | {taskId} | 恢复已存在任务会话 |
cancelTask | {taskId, reason?} | 取消当前轮/排队任务 |
cleanup | {taskId, scope?} | record/files/all |
bulkCleanup | {statuses?, olderThanMs?, deleteFiles?} | 按状态批量清理任务(UI 只传终态;API 不强制终态) |
listFiles | {taskId} | 任务目录清单 |
readSandboxFile | {taskId, relPath, maxChars?} | 文本预览 |
previewReturn | {taskId, parts?} | 生成可编辑返回预览 |
returnToMain | {mainSessionId, text} | 注入一条用户消息(手动确认后) |
exportEntries | {taskId, entries, targetDir, mode?, conflict?, remember?} | 执行一次导出 |
listExports | {} | 导出记录 |
undoExport | {exportId} | 撤销复制导出 |
getDiagnostics | {} | 诊断/stderr/兼容性 |
restartCore | {} | 重启侧车(会中断 live 任务) |
getLegacyTask | {taskId} | 旧版迁移任务的只读记录 |
字段级契约见 docs/PROTOCOL.md。
<DSH_HOME>/
isolation-pod/
pod.db SQLite WAL(配置/任务/审计/导出/旧日志)
core.log 侧车滚动日志
pod.db-wal, pod.db-shm SQLite WAL 运行时文件
isolation-pod.json 仅 v0.1.x 遗留;首次迁移后改名 .json.bak
profiles/<profile>/cordis.patch.yml 开发用 patch 行(如使用)
sessions/... DSH 会话日志(官方会话的事实来源)
<sandboxRoot>/
<subdir?>/<taskId>/ 任务目录(subdir 为空则为 <taskId>)
<targetDir>/
.isolation-pod-undo/<exportId>/ 覆盖式导出的撤销备份
maxExports 时,启动时或每次导出后的清理会连同撤销备份一起移除;retentionDays 只删任务记录,不删文件。.json 迁移后保留为 .bak,不要手工删除(回滚需要)。core.log.1(保留当前 + 1 份);不记录文件内容、主会话上下文或 token。| 位置/能力 | 隔离环境自身 | 用户手动操作 |
|---|---|---|
| 沙箱目录内 | 可读写 | 可查看/导出/清理 |
| 沙箱目录外 | 只读 | 默认只读 |
| 主会话历史/上下文/消息流 | 不可注入 | 用户确认后可注入一条返回消息 |
| 工具 | 仅白名单;guard 拒绝其他 | 可在配置中调整(影响新任务/新轮) |
| 导出目标 | 不可写 | 用户确认后可复制/移动 |
| 临时目录 | DSH workspace-write 允许写入;系统提示要求写沙箱 | 已知限制 |
一句话:沙箱内可读写、沙箱外只读;读取范围不设限;写沙箱外/返回主会话必须用户手动确认; 导出每次单独授权;任务对主会话默认完全不可见。
顶部黄条只针对用户主会话。任务会话的 cwd 是沙箱根,不应参与该告警;Client 会排除任务
会话与 subagent 会话并选择用户主会话,Host 若收到 pod 会话 ID 则解析回任务记录的
mainSessionId。只有主会话工作区确实包含沙箱根时才会提示。
lib/bin/<platform>-<arch>/:
win32-x64、linux-x64、darwin-x64、darwin-arm64(后续可扩展)。注意目录名使用
Node 的 process.platform(win32-x64),而 Release 资产/zip 名使用 windows-x64。node scripts/fetch-core.mjs 可按版本/平台下载并校验 SHA-256。a34a701da220fc5c1f6b74eb027ac167c22c9284e0ff460684ccd9a42d442701。发布 zip 内含
构建时间戳,哈希随重建变化;以同目录 SHA256SUMS.txt 为准。| 现象 | 原因 | 处理 |
|---|---|---|
| 侧边栏没有「隔离舱」 | 插件未启用/未重启/缺 webServer | 检查插件页面与安装方式;重启;确认 profile 有 Web UI |
/status 连接失败 | Host 未加载或端口不对 | 用桌面版设置/dsh web 打印的 URL;重启 |
coreStatus: missing/down/restarting/incompatible | 二进制缺失/崩溃/版本不匹配 | 检查 lib/bin/<platform>-<arch>/;到「诊断」重启;用同一版本 Host+侧车 |
CORE_UNAVAILABLE | 侧车未就绪/重启中 | 等待或诊断页重启核心 |
| 面板一直「加载中」/令牌错误 | 页面早于插件加载/token 失效 | 重载页面;桌面版退出重开;Web 版重开 dsh web URL |
| 启动按钮灰色 | 未配沙箱根/主会话为空/描述为空 | 到配置保存绝对路径;选择一个主会话 |
启动任务报 ROOT_PROTECTED | 沙箱根是文件系统根/主目录/DSH 数据目录/cwd/系统目录,或包含它们 | 换一个工作区之外的专用目录 |
启动任务报 BAD_SUBDIR | 子目录为绝对路径、层级 >8、单段 >64 字符或含非法/保留名 | 按错误提示修正子目录 |
| 黄条「沙箱在主会话工作区内」 | 沙箱根确实在主会话 cwd 内 | 移到工作区外;任务会话自身 cwd 不算 |
| 任务一直「运行中」 | 模型/工具耗时或超时 | 等或停止;检查诊断/超时设置 |
| 打开任务没有对话内容 | 旧版任务只读/会话日志被清理 | 查看旧执行记录;新任务重跑 |
| 导出目标报错 | 目标在沙箱内/非绝对路径 | 选沙箱外的绝对目录 |
| 撤销冲突 | 目标被修改/删除(且有哈希可校验) | 属预期;用新导出的复制模式重试 |
| 旧记录撤销不安全 | 旧版/无哈希记录不校验;撤销会直接删除目标,覆盖前也没有备份 | 先手工备份目标;不要依赖旧记录的撤销 |
| 插件出现两份入口 | bundle + patch 行同时启用 | 只保留一种安装方式并重启 |
core/ Rust 侧车(Cargo)
lib/ Host 半 + 构建后的 lib/client.js + lib/bin
src/client/ Client TypeScript/React 源码
scripts/ build-client / build-core / fetch-core / check-version / package
test/ host / client / core e2e
docs/ ARCHITECTURE / PROTOCOL / MIGRATION
locale/ icon.svg 插件元数据(bundle 安装)
cordis.patch.yml bundle 补丁
pnpm install
pnpm run build:client # src/client -> lib/client.js
pnpm run build:core # cargo release -> lib/bin/<platform>-<arch>/
pnpm run build # client + core
pnpm run test:host # Host 测试(桩 DSH + 假/真侧车)
pnpm run test:client # Client 测试
pnpm run test:core # Rust 测试
pnpm run test:e2e # 构建侧车 + 真实二进制 e2e
pnpm run check # 版本/元数据/协议/schema/locale 一致性
pnpm run release:zip # 本地打包(dist/)
环境:Node 24(构建/测试)、pnpm、Rust stable ≥ 1.85;Windows 需要 C 编译器构建
rusqlite bundled(MSVC Build Tools 或 MinGW gcc)。构建/测试产物不随包分发。
package.json、core/Cargo.toml、lib/version.js、CHANGELOG 标题;
协议/schema 与 docs/PROTOCOL.md 一致。scripts/check-version.mjs 校验元数据、locale、patch、workflow、Client bundle。vX.Y.Z,GitHub Actions 构建四平台侧车与 Client,打包 zip、
裸二进制与 SHA256SUMS.txt,创建 Release。| 项目 | 命令 | 本地结果(2026-10-17) |
|---|---|---|
| Rust 质量门 | cargo fmt --check / clippy -D warnings / cargo test --locked | 通过;51 lib + 4 integration |
| Host | pnpm run test:host | 64/64(含真实侧车用例) |
| Client | pnpm run test:client + tsc | 41/41 + 类型通过 |
| Client 构建 | pnpm run build:client | ≈204.9 KiB,externals 仅 React |
| 侧车 e2e | pnpm run test:e2e | 4/4(真实二进制) |
| 元数据 | pnpm run check | 通过 |
| 发布打包 | pnpm run release:zip | Windows x64 zip + 裸侧车 sha256 校验通过 |
| 真机面板 | 手工 | Windows 桌面版 0.2.1-rc.2 手工走查;验收清单见使用教程附录 C(非逐条记录) |
| 术语 | 含义 |
|---|---|
| 主会话 | 用户当前正在使用、用于正常对话的 DSH 会话;任务不得自动写入它 |
| 任务 | 一条隔离舱记录,对应一个独立 DSH 普通根会话 |
| 任务会话 / 隔离会话 | 任务自己的 DSH 会话;cwd = 沙箱根;不加入 workspace |
| 沙箱根目录 | 用户手动指定的唯一可写根;任务目录在其下 |
| 任务目录 | <sandboxRoot>/<subdir?>/<taskId> |
| 任务操作条 | 官方会话输入框上方的隔离舱 dock |
| 恢复卡片 | 任务会话不 live 时接管官方 composer 的只读恢复 UI |
| 侧车 | Rust 进程 isolation-pod-core |
| Host 半 | lib/index.js 等 Cordis 插件代码 |
| Client 半 | lib/client.js,页面内面板/操作条 |
需求说明.md 是冻结基线;本实现的有意差异:
| 基线 | 本实现 |
|---|---|
| 每次任务/会话需手动入口 | 使用普通根会话,不加入 workspace,只从隔离舱面板打开 |
| 自绘独立界面 | 官方会话面板;任务操作条/恢复卡片注入 |
| 只有单轮 | 支持官方输入框续聊与重启恢复 |
| 并发超限拒绝 | 默认 FIFO 队列(queueEnabled) |
| 清理只描述单任务 | 支持 record/files/all 与批量清理终态任务 |
| 导出/撤销 | 增加冲突策略、BLAKE3、覆盖备份、复制撤销冲突检测;移动不提供 UI 撤销 |
| 工具白名单 | 仅上限;preset 缺失不清空,guard 强制执行 |
| Windows | Rust 跨平台;Windows x64 手工验证,其他平台 CI 构建 |
| 配置 | 增加 queue/preview/exportVerify/probeMode/autoResumeOnOpen/logLevel/maxTasks/maxExports/retentionDays |
| 低版本兼容 | 只支持 DSH 0.2.1+;v0.1.3 数据自动迁移 |
使用教程.md:从安装到验收的分步走查。需求说明.md:功能需求基线(冻结)。CHANGELOG.md:版本历史。docs/ARCHITECTURE.md:架构与设计决策。docs/PROTOCOL.md:协议与 API 契约。docs/MIGRATION.md:迁移与回滚。NOTICE.md:第三方依赖与许可。