# 2.4.2 即时迁移与标题修复验收 正式版本:2.4.2。验收候选:2.4.2-rc.4;正式版仅调整版本和发布文档,运行逻辑相同。 ## 人工验收结论(2026-10-26) 用户在 DSH Desktop 0.2.1-rc.2 / Windows 上确认: - 空闲会话拖动后立即出现在目标工作区,标题正常。 - rc.4 修复后不切换会话即可继续发送,未再出现“会话不可用”。 - 运行中拖动选择取消:任务继续、会话不移动。 - 明确选择停止任务并迁移:任务停止,迁移后可在当前界面继续发送。 - 彻底退出重启后标题、历史、归属正常,继续发送成功。 证据来源:维护者在本次验收会话中先确认“一切正常”,随后按最后三项测试回复“都成功。进入发布流程和issue解决流程”。这是维护者本机验收,不代表原报告者已在旧版 DSH 复测。 用户已在 rc.2 确认迁移后立即显示在目标工作区,且未出现未命名会话;随后发现当前输入框显示“会话不可用”,手动切走再切回才恢复。rc.3 尝试同步重新打开,但用户复验仍不可用,并出现重新连接失败提示。rc.4 改为等待引用释放后打开,用户随后确认通过。 ## 迁移后的当前对话 官方 SessionController 在 dispose 时发布 api-session/removed;客户端 Session.handleRemoved 将 removed 置为 true,后续 added 事件只更新列表,并不清除此标记。因此后端已恢复的 Agent 对应的旧界面仍不可用。rc.3 在迁移 RPC 结束后检查仍选中的会话,仅在 removed 时通过 uiWorkspace.clearMain/openSession 释放旧视图并重新打开,等待新会话打开。失败回滚也执行同样检查;用户切换到其他会话或插件卸载后不主动跳转。不改宿主文件或私有 removed 字段。 rc.3 漏掉了延迟释放:clearMain 仅立即释放主视图引用,React Provider 的其他引用要等界面更新才释放,立刻 openSession 会重新持有 removed 的旧对象。rc.4 用 sessions.retainInfo 观察旧 binding 的实际退出后再打开;最多等待 3 秒,插件卸载会取消等待。等待期间用户选了其他会话则不重新打开。 新增已安装客户端验证:执行 Desktop 内的真实 ClientSessions / SessionManager / Session 代码,使用真实 Cordis,替换界面 store 和未使用的传输边界。确认 added 不清除 removed、双引用下同步重新取得旧对象、延迟释放最后引用后才能取得 removed=false 的新对象。该验证不运行 React 界面,不能替代 Desktop 复验。 若其他界面仍持有旧会话引用,或重新打开失败,明确提示彻底退出并重启,不重复执行物理迁移。自动回归覆盖成功、回滚、连接报错、用户切换、正常界面和插件卸载;完整 Desktop 界面、草稿及预设保持情况仍需实际验收。 ## 行为 - 插件观察官方 agents.create/resume,保留返回的生命周期 dispose;不修改持久化 writer、不可变 Session header 或安装文件。 - 空闲且已接入生命周期的会话:锁定迁移操作,阻止新请求及后台恢复,等待官方 dispose 排空并关闭 writer,真实搬移档案,通过官方 SessionController.resolveAgent 重新按宿主预设加载。 - 运行中会话:弹窗明确显示“停止任务并迁移”;取消不调用迁移。状态在确认后发生变化时,后端返回 stop-required,不擅自停止。 - 放行操作使用 AsyncLocalStorage 限定为当前迁移的恢复调用,不放行其他并发恢复。旧 Agent 引用在替换后拒绝发送。 - 迁移失败沿用文件和工作区归属回滚,并请求宿主从原位置重新加载。若重新加载失败,明确返回错误,不伪称全部成功。 - 热更新前已打开、没有保留生命周期句柄的会话不强行释放。完全重启一次后重新打开会话即可接入;未知后端仍保留原安全检查。 - 拖动迁移不自动创建 pending。历史 API 的排队能力和已有队列保持兼容;没有明确停止授权的后台任务不取消正在运行的 Agent。 - 活跃子代理迁移暂不支持;不能在其父任务仍持有生命周期时单独卸载。 ## Issue #10:标题 原实现调用底层 table.update,但已安装宿主的缓存表使用 get/put。现在以完整 identity/rows 读取并写回,在 attachSession 发布新归属之前对齐 identity.cwd;保留 title 行,移除旧 workingDirectory 行。attach 失败恢复原 identity/rows。 本机“标题保留测试”归档后,标题仍保存在新版 per-record 投影缓存中;修复面板原来只读取旧 session_projcache.json 汇总文件,因此误显示“未命名会话”。现在扫描、归档、预览和备份列表按内存缓存、新版单记录文件、旧版汇总、档案标题的顺序读取。回归测试覆盖新旧缓存共存、内存更新和损坏缓存降级。 报告者 DSH 0.2.0-rc.2 环境尚未直接复现;这是发现并修复的具体代码缺陷,不声称已完成该环境验收。 ## 自动验证 - 常规套件包含即时迁移的 DOM 确认/取消、无自动排队、生命周期并发拒绝和卸载恢复检查。 - test/live-migration.test.mjs 的可选集成项使用从本机 Desktop 提取的 DSH 0.2.1-rc.2、真实 Cordis、SessionStore、AgentRegistry、AgentLoop、JSONL/Zstd writer 和原生文件锁。 - 检查真实 Agent 创建、释放、物理迁移、目标路径恢复、继续追加、失败回滚后恢复原路径,以及运行中拒绝/明确停止后迁移。 - 集成测试的 SessionController 入口使用精简实现调用真实 agents.resume;没有启动完整 Desktop、加载真实用户预设或调用在线模型。实际预设、权限与模型恢复依赖下面的 Desktop 人工验收。 - DSH_TEST_NODE_MODULES 指向已有 runtime/node_modules,运行 npm run test:installed-host;未配置时明确 skip。 - rc.2 本机 Windows / Node 22.23.2:npm run check 通过,319 项通过、1 项真实宿主可选测试按预期 skip;单独配置真实宿主后 npm run test:installed-host 的 3 项全部通过。rc.3 增补当前对话重新打开的回归检查。跨平台 CI 尚未运行。 - rc.3:npm run check 通过,325 项通过、1 项可选测试跳过;语法、打包预检和 git diff --check 通过。新增的 6 项界面回归使用 DOM 与宿主服务替身,尚不能替代 Desktop 人工复验。 - rc.4:npm run check 通过,327 项通过、2 项宿主可选测试跳过;配置真实宿主后 npm run test:installed-host 的 4 项全部通过,包括上述客户端引用释放复现。语法、打包预检和 git diff --check 通过。Desktop 人工复验通过,见本文开头。 ## Desktop 验收 1. 保存正在做的工作,从应用菜单或托盘彻底退出 DSH,再启动。自检版本应为 2.4.2-rc.4。 2. 新建测试会话并命名“标题保留测试”,发送一句消息,等回复结束。拖到 B,确认后应直接显示在 B,无 pending、无需重启。 3. 不切换到其他会话,在 B 当前界面直接连续发两条消息,确认输入框可用、正常回复,模型/预设/权限及未发送草稿保持预期,有效工作目录为 B。 4. 让另一个测试会话执行可随时停止的任务,生成回复期间拖动。先取消,原任务继续;再次拖动选择“停止任务并迁移”,确认任务停止后会话出现在 B,可继续发送。 5. 重启后标题、历史、归属和工作目录仍正确。分别检查手动标题和自动生成标题,并在归档后检查设置中的会话修复列表标题。若异常,保留测试会话,不重复强行搬移。 发布后在 issue #10 说明修复及升级步骤,并邀请原报告者在 DSH 0.2.0-rc.2 复测;待其确认后关闭。