隔离舱 Isolation Pod
在 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 |
文档索引
本文中的「隔离舱」「任务」「任务会话」「主会话」定义见 术语。
需求基线与本实现的差异集中在 规格与本实现的差异。
特性
- 主会话零自动痕迹:任务在独立普通根会话中运行,不向主会话写消息、不进入主会话模型上下文;
唯一注入入口是用户手动确认的「返回主会话」。
- 官方会话界面:打开任务时通过
uiWorkspace.openSession 进入 DSH 官方会话面板,直接展示
官方消息流、工具卡片、思考过程与输入框;隔离舱不自绘转写。
- 沙箱由 DSH 强制:任务会话 cwd = 沙箱根目录,
sandbox/mode=workspace-write;沙箱外写入由
DSH 文件沙箱硬拒绝,不依赖提示词自觉。首轮模型轮次之前还有一次越界写探针。
- Rust 内核:配置、任务状态机、FIFO 队列、每轮超时、租约、文件清单/预览、导出/撤销、
v0.1.3 迁移、审计与诊断都在侧车中完成;Host 只保留 DSH 集成与进程内句柄。
- 任务队列与重启恢复:超过并发上限自动排队;宿主重启后可重新打开/恢复任务会话继续对话。
- 导出安全:复制/移动、覆盖/跳过/重命名、BLAKE3 哈希、覆盖前备份、有哈希时的撤销冲突检测;
每次导出单独确认,不自动延续授权。
- 工具白名单执行:白名单只作上限,由
tools.guard 强制;preset 缺失不会清空白名单。
- 跨平台:插件自身的目录/文件/导出/清理不再依赖 PowerShell,Rust 侧车提供同一套实现。
- 可诊断:
/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>,占用并发槽或入队;
- Host 在沙箱根 cwd 上创建普通根会话,在 setup 窗口写入
sandbox/mode、
approval/policy=never、挂载 preset、安装工具 guard、注入系统提示段;
task.markRunning 之后执行越界写探针;探针通过后,发送一条干净的 任务:<描述> 用户消息;
- 官方会话面板实时展示执行过程;任务操作条提供面板/文件/返回/导出/停止;
- 完成后可继续对话、手动返回主会话、手动导出文件或清理;主会话全程不被自动写入。
环境要求
- DSH 0.2.1+(桌面版或
dsh web;本地使用 0.2.1-rc.2 桌面版验证)。
- 一个带 Web UI 的 profile;CLI/TUI profile 没有
webServer 时插件不会激活。
- 宿主侧 Node.js(由 DSH 提供);运行期不需要用户安装 Node 包。
- Rust 侧车二进制:
- Windows x64:仓库内已带
lib/bin/win32-x64/isolation-pod-core.exe;
- 其他平台:下载 Release 中对应平台包,或从源码构建(需要 Rust stable ≥ 1.85)。
- 可选:
ISOLATION_POD_CORE_BIN 指向自定义侧车路径。
安装
方式 A:bundle(推荐)
- 打开 DSH 侧边栏 →「插件」;
- 「添加插件」→「安装第三方插件」;该入口支持 npm 包、Git 仓库和本地目录;
- 选择本仓库目录的绝对路径(或 Release 解压目录),安装;
- 确认
dsh-isolation-pod bundle 已选中、插件行启用;
- 页面提示「请重启 DSH 使更改生效」时重启一次。Host 半(
lib/index.js)被替换后 Node 会
按 URL 缓存旧模块,必须重启;只有 Client 半更新可以热重载。
方式 B:patch 行(开发/回退)
在 <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。侧边栏出现「隔离舱」入口。
升级与回退
- 升级:替换包 → bundle 重新安装/更新,或
git pull && pnpm install && pnpm run build;
Host 改动后重启 DSH。
- 回退到 v0.1.3:见
docs/MIGRATION.md §5;注意新版数据只在
pod.db 中,旧版不读取。
- 不要手工编辑运行中的
pod.db;停机后可只读检查。
快速开始
- 配置沙箱根目录:面板「配置」→ 输入一个工作区之外的绝对路径(例如
E:\pod-work),
或点「选择目录」;保存。
- 新建任务:「新建」→ 填写任务描述(可附沙箱子目录)→ 选择主会话 →「启动隔离任务」。
- 查看执行过程:任务启动后自动打开官方会话;也可在任务列表点「打开会话」。
- 继续对话:在官方输入框直接发送;sandbox、approval、guard 与系统提示段保持不变。
- 停止:任务操作条或官方输入框的停止;状态变为「已取消」。
- 返回主会话(可选):任务操作条「返回」→ 勾选/编辑预览 → 确认;主会话只收到一条
精简的用户消息。
- 导出(可选):任务操作条「导出」→ 勾选文件、指定沙箱外目录、选择方式/冲突策略 →
二次确认;每次导出都重新确认。
- 清理:任务列表或详情中的「清理」;可只删沙箱文件,或清理记录与文件(HTTP
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 会话使用官方输入框,不替换。
主会话与任务会话
- 任务会话是普通根会话,不是 subagent;它不加入任何 workspace,不出现在侧边栏的
workspace 列表;可能出现在 DSH 会话搜索/历史中。
- 打开任务后官方主视图会停在该任务会话上;这是任务视图,不是「用户主会话」。
- 返回主会话、读取主会话上下文使用任务记录的
mainSessionId;新建任务的主会话选择使用
用户主会话列表(排除 pod 任务会话与 subagent 会话)。
- 顶部黄条「沙箱根目录位于主会话工作区内」只在用户主会话 cwd 确实包含沙箱根时出现;
任务会话自身 cwd(= 沙箱根)不会触发它。
任务、队列与恢复
状态
| 状态 | 含义 |
|---|
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 看门狗。
- 超时后用户仍可在 live 会话继续对话(下一轮重新计时)。
恢复
autoResumeOnOpen=true(默认):打开任务时若会话不 live,Host 用 task.reattach +
agents.resume 恢复隔离 setup,再打开官方会话;不自动发消息。
- 恢复失败时仍打开历史;composer 只读恢复卡片提供「恢复隔离会话」。
- 旧版迁移任务没有可恢复的 Agent,只保留只读记录。
- 官方 UI 自行恢复任务会话时,Host 的
agent/created 安全网会在首轮前补齐隔离 setup。
停止
- 任务操作条「停止」或官方输入框的停止都会取消当前轮。
- 取消只影响该任务,不写入主会话。
返回主会话
- 任务操作条「返回」:可选择包含状态、最近结论、附带一个文本文件,生成可编辑预览
(≤ 4000 字);编辑后点「确认返回主会话」。
- 确认后只向主会话注入一条用户消息(≤ 8000 字);主会话必须当前打开(live),否则
返回
MAIN_SESSION_NOT_LIVE。
- 默认不返回任何内容;返回与导出是独立操作,互不触发。
- 返回内容只来自任务摘要/用户编辑/任务目录中的文本文件;二进制文件不会被注入。
导出与撤销
- 任务详情/任务操作条「导出」:勾选任务目录中的文件或目录,指定沙箱之外的绝对目标目录,
选择方式(复制/移动)与冲突策略(覆盖/跳过/重命名),二次确认。
- 每次导出都是单次授权;
allowRememberChoice 只允许预填上次目标路径,仍需每次确认。
- 撤销:导出记录页只对复制模式提供撤销。覆盖前目标会被复制到
<targetDir>/.isolation-pod-undo/<exportId>/;撤销在 exportVerify 开启时校验 BLAKE3 哈希
(哈希在导出时总会记录),目标被修改/删除或变成链接时返回冲突。旧版/无哈希记录不会校验,
撤销会直接删除目标,且无法恢复被覆盖的原文件;请先备份。 移动模式在 UI 中不提供撤销。
- 导出目标不能位于沙箱内;导出不会修改沙箱源文件(移动模式成功后会删除源文件)。
- 上限:5000 文件 / 2 GiB 总量 / 单文件 1 GiB。
文件与预览
- 任务详情「文件」列出任务目录内容(深度 ≤ 8、最多 2000 项);符号链接不跟随。
- 文本预览支持 UTF-8、UTF-16 LE/BE(BOM),单文件受
previewBytes 与 previewChars 限制;
二进制文件返回明确提示,不渲染乱码。
- 预览只读,不修改任务文件;路径逃逸/绝对路径/
.. 会被拒绝。
清理
- 任务详情/列表:
- 仅删除沙箱文件:删除任务目录,保留任务记录;
- 清理任务记录与文件:删除记录(及审计/旧日志)并释放 Agent;
- 批量清理终态任务:只处理已结束的任务,可选同时删除沙箱文件;运行中/排队任务不会被批量选中。
- 沙箱根目录本身永远受保护;清理不触碰主会话,也不触碰沙箱外文件。
- 启动时按
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 | 打开任务时尝试恢复会话 |
|
sandboxProbeMode 语义:
- 沙箱外写入被允许:两种模式都失败,任务不启动;
- 结果不明确(
ambiguous/failed):strict 失败,warn 记录警告后继续;
- 沙箱根是盘符根(无父目录可探):
skipped-no-parent 通过并警告。
HTTP 接口
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>/ 覆盖式导出的撤销备份
- 任务记录、导出记录与配置只由侧车写 SQLite;Host 只读缓存。
- 导出记录超过
maxExports 时,启动时或每次导出后的清理会连同撤销备份一起移除;retentionDays 只删任务记录,不删文件。
- 旧版
.json 迁移后保留为 .bak,不要手工删除(回滚需要)。
- 侧车日志达到 1 MiB 时轮转为
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。
- 仓库提交了 Windows x64 发布二进制;其他平台由 GitHub Actions 构建并作为 Release
资产提供。
node scripts/fetch-core.mjs 可按版本/平台下载并校验 SHA-256。
- 本机验证:Windows x64。Linux/macOS 只用 CI 构建,未做本机面板验收。
- 二进制不随包附带 MinGW/VCRUNTIME 运行库;PE 导入仅 Windows 系统 DLL(含 UCRT API sets、
kernel32/ntdll/bcrypt 等)。未做代码签名,SmartScreen/Gatekeeper 可能提示。
- 当前 Windows x64 侧车:1,902,592 B,SHA-256
a34a701da220fc5c1f6b74eb027ac167c22c9284e0ff460684ccd9a42d442701。发布 zip 内含
构建时间戳,哈希随重建变化;以同目录 SHA256SUMS.txt 为准。
已知限制
- Fork 会脱离隔离:官方会话的 Fork 会创建一个新的普通会话,该会话没有隔离舱 setup;
任务操作条会警告。不要在任务会话中使用 Fork 继续隔离任务。
- DSH 临时目录:workspace-write 下平台临时目录可写;系统提示要求临时文件写沙箱,
但 Host 不能用同步方式阻止 shell 写 TEMP。
- 旧版任务只读:v0.1.3 迁移任务没有可恢复 Agent,只能查看旧执行记录/文件/导出。
- 任务会话不在 workspace 列表:它仍可能出现在 DSH 会话搜索/历史中;不会向主会话写入。
- 官方 UI 命令/权限控件:可能改变模型/审批等设置;Host 会重新断言 sandbox/approval,
但 UI 可能短暂显示改动。
- Shell 工具:白名单只能限制工具名;shell 内部写路径由 DSH 沙箱约束,Host 不做命令解析。
- 未签名二进制:Windows/macOS 首次运行可能被系统安全提示拦截。
- Linux/macOS 面板验收:产物由 CI 构建,未做本机人工走查;路径/外观差异可能仍存在。
- 网络:侧车不联网;插件运行不需要网络,构建/下载二进制需要网络。
- DSH 版本:只支持 0.2.1+;升级 DSH 后需重新验证 compat。
故障排查
| 现象 | 原因 | 处理 |
|---|
| 侧边栏没有「隔离舱」 | 插件未启用/未重启/缺 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。
- Host 半改动必须重启 DSH 才能加载;Client 半可热重载。
验证矩阵
| 项目 | 命令 | 本地结果(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 数据自动迁移 |
相关文档
许可
MIT,见 LICENSE。第三方组件见 NOTICE.md。