# 从 v0.1.3 迁移到 v0.2.0 v0.2.0 是一次破坏性重构:持久化从 JSON 改为 SQLite,隔离任务从 subagent 子会话改为普通根 会话,界面改用 DSH 官方会话面板,HTTP 方法表也重新设计。本文给出可回滚的升级步骤、 数据迁移细节、行为差异与验收清单。 - 架构背景:[`ARCHITECTURE.md`](ARCHITECTURE.md) - 字段级契约:[`PROTOCOL.md`](PROTOCOL.md) - 面向使用者的完整说明:[`../README.md`](../README.md)、[`../使用教程.md`](../使用教程.md) > 适用范围:v0.1.x(最后版本 v0.1.3,支持 DSH 0.1.7)→ v0.2.0(要求 DSH 0.2.1+)。 > 先升级 DSH,再升级本插件;v0.2.0 不再兼容 0.1.7。 ## 1. 升级前准备 1. **退出 DSH**(桌面版退出应用;`dsh web` 停止进程),确保没有旧进程正在写 `isolation-pod.json`。 2. **备份以下内容**: - `\isolation-pod.json`:v0.1.x 的配置、任务、导出记录与转写镜像; - `\profiles\\cordis.patch.yml`:旧安装的 patch 行; - ``(可选):任务产物; - 整个 ``(推荐,回滚时最省事)。 `` 默认是 `%USERPROFILE%\.dsh`;桌面版 profile 通常是 `desktop`。 3. 记下旧的沙箱根目录、工具白名单、超时、并发与 preset;升级后逐项核对。 4. 确认 DSH 已是 **0.2.1+**;如果仍停留在 0.1.7,请继续使用 v0.1.3。 ## 2. 取得并安装 v0.2.0 ### 2.1 取得包与侧车二进制 二选一: - **Release 包**:下载 `dsh-isolation-pod-0.2.0--.zip` (例如 `dsh-isolation-pod-0.2.0-windows-x64.zip`),解压到任意目录。 包内已包含对应平台的 `lib/bin/-/isolation-pod-core[.exe]`(Windows 目录是 `win32-x64`,发布资产名是 `windows-x64`),无需 Rust。 - **源码**: ```powershell git checkout v0.2.0 pnpm install pnpm run build ``` 需要 Rust stable ≥ 1.85;`build:core` 会把二进制放入 `lib/bin/`。 如果只缺二进制,也可用 `node scripts/fetch-core.mjs` 从 Release 下载并校验。 若 `lib/bin/` 为空或平台不匹配,插件仍会加载,但 `/status` 显示 `coreStatus: missing`,任务接口返回 `CORE_UNAVAILABLE`。可用 `ISOLATION_POD_CORE_BIN` 指向一个自定义二进制路径。 ### 2.2 安装(两种方式只选一种) **推荐:bundle 安装** 1. DSH 侧边栏 →「插件」; 2. 「添加插件」→「安装第三方插件」→ 支持 npm 包、Git 仓库和本地目录; 3. 填入解压/克隆出的**本地目录绝对路径**,安装; 4. 确认 `dsh-isolation-pod` bundle 已选中、插件行处于启用状态; 5. 如果页面提示「请重启 DSH 使更改生效」,重启一次。Host 模块(`lib/index.js`)被替换后 Node 会按 URL 缓存旧模块,必须重启;只有 Client 半的更新可以热重载。 **回退/开发:patch 行** 在 `\profiles\\cordis.patch.yml` 末尾追加: ```yaml - insert: - id: dsh-isolation-pod name: '<包绝对路径>\lib\index.js' ``` 保存后宿主会重新应用 profile;Host 半有改动时同样需要重启。 **不要**在已用 bundle 安装的 profile 中保留或追加这条 patch 行:Host 的重复激活保护会忽略 第二个实例,但仍可能出现重复的 Client 入口与配置混淆;只保留一种安装方式。 ### 2.3 清理旧安装 - 删除 v0.1.x 留下的旧 `- insert:` 行(旧 `name` 指向旧仓库的 `lib\index.js`); - 旧仓库目录可以保留作回滚备份,但不要让旧 patch 行继续生效; - 如果旧版是通过 bundle 安装的,先在插件页面移除旧 bundle,再安装 v0.2.0。 ## 3. 首次启动与自动迁移 启动 DSH 后,Host 会拉起侧车;侧车执行 `initialize`,并检测 `\isolation-pod.json`: - 数据库不存在或为空时,执行一次性导入; - 导入配置:同名字段原样迁移;新增字段取 v0.2.0 默认值; - 导入任务:id、主会话、描述、状态、目录、轮次、旧日志(进入 `legacy_log`); - 导入导出记录与条目;旧记录没有 v0.2.0 的哈希/覆盖备份,撤销既不会做哈希校验,也无法恢复 被覆盖的原文件;需要可验证撤销时请重新导出。 - 把旧 `running/queued` 任务按新状态机映射为 `interrupted`; - 成功后把原文件改名为 `isolation-pod.json.bak`; - 局部损坏的记录会被跳过并写入诊断,不阻塞其余数据。 > 不要把 `.bak` 手工删掉;回滚需要它。 验证(端口以桌面版设置或 `dsh web` 启动时打印的 URL 为准): ```powershell curl.exe -s http://127.0.0.1:/isolation-pod/status ``` 关注: - `ok: true` - `pluginVersion: "0.2.0"`、`coreVersion: "0.2.0"` - `protocol: 1`、`schemaVersion: 1` - `coreStatus: "ready"` - `dbPath` 指向 `\isolation-pod\pod.db` - `diagnostics` 中有迁移摘要 打开「隔离舱」面板: - 「任务」页能看到旧任务,标记为**旧版任务**; - 旧任务只能看只读执行记录,不能恢复 Agent; - 新任务可以打开官方会话、继续对话、重启恢复。 ## 4. 数据与行为差异 ### 4.1 持久化 | 项目 | v0.1.3 | v0.2.0 | |---|---|---| | 状态文件 | `\isolation-pod.json`,防抖写盘 | `\isolation-pod\pod.db`,SQLite WAL + 事务 | | 写入方 | Host 半 JS | Rust 侧车;Host 只读缓存 | | 旧数据 | — | 自动迁移;原文件保留为 `.bak` | | 容量上限 | 任务/导出各 200 条硬编码 | `maxTasks` / `maxExports` 可配置(默认 200) | | 自动保留 | 无 | `retentionDays`;仅启动时清理终态任务记录,不删文件 | 数据库只应由侧车写入。停机后可用任何只读 SQLite 工具检查,**不要**在运行中手工改库。 ### 4.2 会话模型 | 项目 | v0.1.3 | v0.2.0 | |---|---|---| | 隔离会话 | `origin: 'subagent'` 的子会话 | **普通根会话**,`cwd = sandboxRoot` | | 查看过程 | 面板自绘转写 | **DSH 官方会话面板**(`uiWorkspace.openSession`) | | 多轮追问 | `followUp` 向进程内常驻 Agent 续发 | 官方输入框直接续聊同一 live Agent;重启后 `resumeTask` | | 打开历史任务 | 自绘详情 | 历史只读打开;未恢复时 composer 显示只读恢复卡片 | | Fork | 未暴露 | 官方 UI 的 Fork 可创建新会话,但**新会话不受隔离舱 setup 约束**;任务操作条会警告 | | 侧边栏 | 隔离舱面板入口 | 任务会话不加入任何 workspace;只从隔离舱面板打开 | ### 4.3 配置字段 同名字段尽量保留;值会经过 v0.2.0 的校验/钳制: | 字段 | v0.1.3 | v0.2.0 | 迁移说明 | |---|---|---|---| | `sandboxRoot` | 绝对路径或空 | 同左 | 归一化:去尾部重复分隔符;盘符根保留一个分隔符 | | `allowWrites` | 布尔 | 同左 | `false` 时任务以 `read-only` 运行 | | `allowedTools` | 6 个工具 | 7 个(增加 `bash`) | 仍是白名单上限,不再与 preset 求交清空 | | `timeoutMs` | 每轮超时 | 同左 | 30 000–7 200 000 ms | | `readContext` | 布尔 | 同左 | 读取最近 12 条主会话消息 | | `maxConcurrent` | 有 | 同左 | 1–8;新增 `queueEnabled` 队列行为 | | `enableExport` | 有 | 同左 | — | | `allowRememberChoice` | 有 | 同左 | 只预填路径,不是授权 | | `presetId` | 默认 `'standard'` | 默认 `''` | 旧值保留;如果新宿主中不存在该 preset,启动任务会报 preset 不可用,请在「配置」重新选择 | | `queueEnabled` | 无 | `true` | 新增 FIFO 队列 | | `maxTasks` / `maxExports` | 硬编码 200 | 200 | 可配置 | | `retentionDays` | 无 | `0` | 0 = 不自动清理;>0 只清记录 | | `previewBytes` | 无独立配置 | `307200` | 单文件预览字节上限;16 KiB–1 MiB | | `previewChars` | 固定上限 | `20000` | 单次预览字符上限;200–20 000 | | `exportVerify` | 无 | `true` | 撤销时校验 BLAKE3(导出时总会记录哈希) | | `sandboxProbeMode` | 无 | `'strict'` | `strict`/`warn` 见 README | | `autoResumeOnOpen` | 无 | `true` | 打开任务时尝试恢复会话;不是"打开面板就恢复所有任务" | | `logLevel` | 无 | `'info'` | trace/debug/info/warn/error/off | 校验规则详见 [`PROTOCOL.md`](PROTOCOL.md) §4。`config.validate` 会把不合规值钳制/忽略并 返回提示,而不是让整个 patch 失败。 ### 4.4 HTTP 方法 | v0.1.3 | v0.2.0 | |---|---| | `getState` | `getState`(新增 `core` / `compat` / `revision`,任务带 `live`/`canResume`) | | `setConfig` | `setConfig` | | `startTask` | `startTask`(可排队;返回 taskId/sessionId/task) | | `getTask` | 移除;状态用 `getState`,打开会话用 `openTask` | | `followUp` | 移除;官方输入框续聊,或 `resumeTask` | | `cancelTask` | `cancelTask` | | `cleanup` | `cleanup`(新增 `bulkCleanup`) | | `listFiles` / `readSandboxFile` | 同名 | | `previewReturn` / `returnToMain` | 同名 | | `exportEntries` / `listExports` / `undoExport` | 同名 | | — | 新增 `openTask`、`resumeTask`、`getDiagnostics`、`restartCore`、`getLegacyTask` | `/status` 结构变化:保留 `build`、`storePath`,新增 `coreStatus`、`protocol`、 `schemaVersion`、`coreVersion`、`dbPath`、`binaryPath`、`sandbox`、`compat`。 `coreStatus` 取值:`starting | ready | down | restarting | incompatible | missing`。 ### 4.5 面板 - 页签:任务 / 新建 / 配置 / 导出记录 / **诊断**(新增)。 - 任务执行过程在**官方会话面板**;面板内的任务详情负责状态、文件、返回、导出、清理与旧记录。 - 任务操作条注入官方 `conversation.input.dock`;未恢复任务的 composer 由只读恢复卡片接管。 - 主会话位置告警只比较**用户主会话** cwd;任务会话自身的 cwd(= 沙箱根)不会触发误报。 - 清理支持:仅删沙箱文件、清理记录与文件、批量清理终态任务;HTTP `cleanup` 另有 `record` 范围(面板不提供单独的「只删记录」按钮);沙箱根始终受保护。 ## 5. 回滚到 v0.1.3 1. 退出 DSH,确认侧车已停止; 2. 卸载 v0.2.0 bundle(或删除 patch 行),恢复 v0.1.3 的 patch 行/仓库; 3. 把 `\isolation-pod.json.bak` 改名回 `isolation-pod.json`; 4. 重启 DSH。 注意: - v0.2.0 期间新建的任务、导出记录、配置改动**只写入 `pod.db`**;v0.1.3 不会读取它们。 回滚后这些数据在旧版本里不可见,但 `.db` 文件会保留,方便再次升级; - v0.2.0 的任务会话是普通根会话,会留在 DSH 会话历史里;v0.1.3 的面板不会识别它们; - 回滚前建议整个 `` 目录备份。 ## 6. 常见问题 | 现象 | 原因 | 处理 | |---|---|---| | `/status` 显示 `coreStatus: missing` / `down` / `restarting` / `incompatible` | 二进制缺失、平台不匹配、不可执行、崩溃重启中,或 Host/侧车版本不配套 | `missing`/`down` 检查 `lib/bin/-/` 与执行权限;`incompatible` 用同一 Release/commit 的 Host 与侧车;`restarting` 等退避结束再试,或到「诊断」页重启核心 | | `PROTOCOL_MISMATCH` / `SCHEMA_MISMATCH` | Host 与侧车来自不同版本 | 用同一 Release/commit 的文件;清理后重装 | | 面板提示「请重启 DSH 使更改生效」 | Host 模块已替换但进程仍跑旧模块 | 重启 DSH;只有 Client 半可热重载 | | 旧任务打开后没有对话内容 | 迁移只导入了旧版保存的转写镜像 | 用任务详情中的「旧版执行记录」查看;原始日志在 `\sessions\` 由 DSH 管理 | | 旧 preset 启动失败 | 旧 `presetId` 在新宿主中不存在 | 在「配置」重新选择可用 preset;或清空 preset 并配置工具白名单 | | 同一插件出现两份入口/重复激活风险 | bundle 与 patch 行同时启用(Host 会忽略第二个实例,但 Client 入口/配置可能重复) | 只保留一种安装方式,重启 | | 顶部黄条说沙箱在主会话工作区内 | 沙箱根确实落在**用户主会话** cwd 内;任务会话 cwd(= 沙箱根)不算 | 把沙箱根移到主会话工作区外,或确认这是你想要的效果 | | 旧导出撤销不安全 | 旧记录没有 BLAKE3/覆盖备份;撤销不会校验,可能直接删除目标且无法恢复原文件 | 先手工备份;需要可验证撤销请用新导出的复制模式 | | 任务会话被 Fork | 官方 UI 的 Fork 会创建不受隔离 setup 约束的新普通会话 | 不要 Fork 隔离任务会话;在任务操作条/README 的限制中已注明 | ## 7. 迁移验收清单 - [ ] DSH 已升级到 0.2.1+,不再使用 0.1.7; - [ ] `\isolation-pod.json` 已备份,首次启动后存在同目录 `.bak`; - [ ] 只保留一种安装方式(bundle 或 patch 行),并已重启加载新 Host; - [ ] `/status`:`build: 2`、`pluginVersion/coreVersion: "0.2.0"`、`protocol: 1`、 `schemaVersion: 1`、`coreStatus: "ready"`; - [ ] 旧任务出现在任务列表并标记「旧版任务」,可查看旧执行记录; - [ ] 旧配置(沙箱根、白名单、超时、并发、preset)已导入并可在「配置」修改; - [ ] 新任务能打开官方会话,状态从 `running` 到 `completed`; - [ ] 官方输入框续聊、停止、返回主会话、导出、撤销各验证一次; - [ ] 重启 DSH:运行中/排队任务标记 `interrupted`;`openTask`/`resumeTask` 可恢复; - [ ] 主会话工作区无自动新增文件、无自动消息、无上下文污染; - [ ] 沙箱根位于主会话工作区外时,不再出现「沙箱在用户工作区内」的误报。