Files
ycode/docs/协作/项目工作空间与后台活动-实施方案-01.md
T

27 KiB
Raw Blame History

项目、工作空间与后台活动实施方案 01

日期:2026-10-21。代码核对基线:590d7ae2fafc2c6b378e316be2f3daab5a98831f。

状态:方案已落地,尚未实施;足以进入技术验证和分阶段开发,不代表 SDK 能力或产品验收已经通过。 本文收敛已讨论的《YCode 项目与工作空间生命周期方案 v2》。不复用 B05 编号,不替代既有协作任务;后续实施编号由协作计划分配。

1. 已确认的产品规则

  1. 一个任务保留同一段主会话,可以从主空间切到新 worktree,再回到主空间。用户不需要另外添加工作区、另开对话或手动结束 Run。
  2. 当前绑定可以变,历史执行归属不能变。 每次 Run 保存实际空间、环境、cwd、模型和权限快照;旧消息、工具记录和后台活动不会随当前绑定迁移。
  3. worktree 是工作空间的来源类型,不是另一层导航。主工作副本与 linked worktree 对应空间在执行层面平级,不要求目录物理嵌套。
  4. 侧栏只做项目折叠、任务平铺,不展开 Session、Run 和进程树。空间管理放在项目菜单或独立入口。
  5. 用户明确要求“创建 worktree 并在里面继续”时,宿主负责创建、登记、切换;仅要求创建时不自动切换。
  6. 只管理 YCode 启动并纳入管理的命令、子 agent 及其受管后代,不扫描、接管或结束外部命令。
  7. 子 agent 与后台进程共用输入区域上方的独立活动条,用户和 agent 都能查询状态、查看日志、请求结束。
  8. 切换不迁移、不自动结束旧活动;清理空间前,才必须核实活动退出、成果保全和其他引用。
  9. 外部删除 worktree 经确认后,原会话自动回到已验证的主空间。离线、权限错误、超时不等于删除;主空间也不可用则暂停。
  10. 自动回退不意味着自动重放工具、自动合并或认定交付完成。合并、删除工作副本、删除分支、任务归档是独立动作。

切换闭环解决后续调用确实进入新空间、旧活动可管、历史不漂移;清理闭环解决成果已处理、受管占用已结束、引用已处置,再安全删除。二者不能合成一个“完成”按钮而省略检查。

2. 概念与生命周期

实体 含义 关系与限制
Project 项目 长期目标、资料、默认配置与任务集合 可关联多个空间,普通办公项目可以无 Git
Workspace 工作空间 某环境中的一份文件工作副本 稳定 ID、单根目录、单环境;根目录不是 OS 安全沙箱
Environment 执行环境 机器、连接状态、运行时与能力 首期只登记本机;手机/网页未来可只是控制入口
Task 任务 目标、验收与交付 首期一个任务一段主会话;完成回复不等于目标验收
Session 会话 消息、工具记录与执行历史 当前绑定可变;切换仍打开原对话
Run 执行 一次受控执行与配置快照 首期每个 Run 的空间不可变;允许同一会话透明续接
Activity 后台活动 受管子 agent、进程或 shell 的生命周期 永远绑定启动时的 Run、环境和空间
项目
├─ 关联空间:主空间 / worktree A / worktree B
└─ 任务(侧栏平铺)
   └─ 主会话
      ├─ 当前绑定 → 一个空间,带修订号
      ├─ Run 1 → 主空间的不可变快照
      ├─ Run 2 → worktree A 的不可变快照
      └─ 后台活动 → 各自启动时的空间,可跨越绑定切换继续运行

空间可以被多个项目引用,共享的是实际文件,不产生隔离;同一路径在不同环境中不是同一空间。空间创建者、当前引用者、控制活动的权限必须分别建模,创建者不因此取得删除其他会话占用空间的权利。

正常链路:讨论 → 创建并切换 worktree → 执行和管理后台活动 → 交付/验收 → 明确完成合并、PR 或补丁等交付 → 返回主空间 → 停止并核实旧活动 → 保全检查 → 清理副本 → 保留历史。验收退回沿原任务继续新 Run;Run 失败不回滚文件;任务归档不自动杀进程或删空间。普通聊天不强制走验收流。

3. 当前代码事实与待验证项

以下为基线源码/本地声明核对,不是新功能交付证明;路径均相对仓库根目录。

位置 当前事实 本次需要补齐
src/shared/workspaces.ts、src/shared/projects.ts 空间记录以 id/name/root 为中心,项目可关联空间 来源、环境、仓库身份、主空间关系与可用性
src/main/ 的项目、空间、会话存储及 src/main/session-factory.ts 现有会话保存 projectId/workspaceId/cwd 等上下文,session-factory 拒绝项目与上下文空间不一致 可变当前绑定和不可变 Run 快照分离;迁移不可只取全局选中空间
src/main/git.ts 现有 Git 分支/HEAD 查询不是 worktree 生命周期管理器 受管创建、验证、清理与成果检查
src/main/agent/claude/claude-kernel.ts Bash/PowerShell 交给 SDK;tool_use/tool_result 形成工具记录 工具返回不等于后台进程退出;接入受管任务生命周期
src/shared/types.ts 中 ToolCallRecord running/ok/error 等描述工具调用 不能直接充当进程注册表
src/main/terminal-host.ts 内存 terminalsMap,PTY 输出、shell 退出、原始输入与 kill shell 生命周期不覆盖每条命令或脱离 shell 的后代
src/renderer/src/components/ChatPane.tsx composeComposer 未传入任务活动,已有 floatingSurface/queuePanel 独立 activitySlot,不挤入互斥授权或队列浮层
src/renderer/src/workbuddy/composer/input-composition.ts 有任务位置接口,尚未形成持久活动接线 复用位置思路而不是宣称已有完整活动栏
src/renderer/src/workbuddy/composer/ComposerControls.tsx 授权/浮层/队列布局,onStop 对应整个 Run 单活动停止不能复用整轮取消
src/renderer/src/workbuddy/conversation/SpecializedBlocks.tsx 的 TaskBlock 消息内子 agent 工具记录 不是独立、持续可控的后台活动栏

本地安装的 Claude Agent SDK 0.3.304 类型声明(node_modules/@anthropic-ai/claude-agent-sdk/sdk.d.ts)包含 task_started、task_progress、task_notification、background_tasks_changed 及 Query 的 stopTask、backgroundTasks。参考声明区域约 6181–6288、3769、3273 行;版本变化应以实际类型名定位。

注意:Query 的 backgroundTasks(toolUseId?) 是将前台任务转为后台的操作,不是列表查询;任务列表观测来自 background_tasks_changed 等事件,不能因名称相似误调用。

这些声明只证明接口存在,不证明当前内核已消费它们,不证明所有 CLI 版本覆盖一致,也不证明任务快照跨 SDK 重启持久化。SDK taskId 是 SDK 任务身份,不是 OS PID,更不保证其全部后代退出。cwd 重绑定、会话 resume、工具边界续接、旧 controller 的后台任务可控性必须做真实 SDK 技术验证。

本方案没有执行原版 WorkBuddy 采集,也不形成新的原版行为结论。后续原版视觉/行为核验仍遵守 AGENTS.md 的 REA 要求。

4. 最小数据契约(拟议,非已有接口)

先使用现有本地存储风格和宿主服务,不预先建设远程调度平台。以下类型表达字段职责,落地时以实际序列化与项目类型约定调整,不把路径或类型草案冒充现有实现。

type ID = string;
type WorkspaceAvailability = 'available' | 'missing' | 'unavailable' | 'unknown';

interface WorkspaceBinding {
  workspaceId: ID;
  revision: number; // 每次成功变更递增,队列/工具校验使用
}
interface WorkspaceSpec {
  id: ID;
  environmentId: ID;
  root: string;
  source: 'directory' | 'git-primary' | 'git-worktree';
  repositoryIdentity?: string; // 宿主核实,不能仅依赖 remote URL
  primaryWorkspaceId?: ID;
  creatorSessionId?: ID;
  availability: WorkspaceAvailability;
}
interface SessionWorkspaceState {
  sessionId: ID;
  projectId: ID;
  binding: WorkspaceBinding;
}
interface ExecutionSnapshot {
  workspaceId: ID;
  bindingRevision: number;
  environmentId: ID;
  cwd: string;
  workspaceIdentity: string;
  modelSnapshotRef: ID;
  permissionSnapshotRef: ID;
}
interface RunWorkspaceRecord {
  runId: ID;
  sessionId: ID;
  execution: Readonly<ExecutionSnapshot>;
  continuationOfRunId?: ID;
  switchOperationId?: ID;
}
interface QueuedWorkspaceRef {
  queueItemId: ID;
  executionTarget: WorkspaceBinding; // 入队捕获,不是发送时随意取最新空间
  status: 'queued' | 'blocked-workspace-change' | 'dispatched' | 'cancelled';
  // 权限快照沿用原规则,不因重新绑定空间而放宽
}

type ActivityState = 'starting' | 'running' | 'stopping' |
  'exited' | 'stopped' | 'failed' | 'unknown';
interface ManagedActivity {
  id: ID;
  kind: 'agent' | 'process' | 'shell';
  ownerSessionId: ID;
  taskId: ID;
  runId: ID;
  execution: Readonly<ExecutionSnapshot>;
  parentActivityId?: ID;
  state: ActivityState;
  readiness: 'not-applicable' | 'pending' | 'ready' | 'failed' | 'unknown';
  trackingCoverage: 'owned-tree' | 'sdk-task-only' | 'shell-only' | 'unknown';
  controllerId: ID;
  sdkTaskId?: string;
  sdkTaskRunId?: string; // SDK 提供的本次任务执行身份,区分 resume/复用
  instanceGeneration: number; // controller/activity 实例代次
  processIdentity?: { pid: number; startedAt: string; instanceId: string };
  logRef?: ID;
  updatedAt: string;
  exit?: { code?: number; signal?: string; reason: string; observedAt: string };
}
interface WorkspaceOperation {
  id: ID; // 幂等键;结果和恢复日志按此关联
  sessionId: ID;
  from: WorkspaceBinding;
  targetWorkspaceId: ID;
  stage: 'preparing' | 'prepared' | 'committed' | 'completed' |
    'failed' | 'reconcile-required';
  continuationRunId?: ID;
  errorCode?: string;
}

readiness 与存活状态分开:running+pending 不能显示“已就绪”;已退出不能残留绿色 ready。退出需要可信证据。SDK 任务没有 OS 身份时不填造 PID;其 coverage 只声明 SDK 所能证明的范围。持久化 PID/时间仅辅助核验,不替代可靠句柄、控制器身份或运行时证明。

绑定的单一事实来源由宿主管理,会话/任务展示引用它,不各存一套会互相覆盖的 currentWorkspaceId。历史快照与活动执行快照只追加,不因重命名、切换或清理重写。日志不保存凭据或无关环境秘密。

5. 空间操作工具与返回契约

建议统一宿主服务,UI 和 agent 共用;工具名称是暂定职责,不是新增已发布 API。

拟议操作 主要输入 成功结果与限制
workspace.createWorktree sessionId、expectedRevision、基准引用、分支、目标路径、continueHere、operationId 已验证空间 ID、创建事实;continueHere=true 才进入切换事务
workspace.switch sessionId、targetWorkspaceId、expectedRevision、operationId 提交后绑定、续接 Run ID;不能只更新 UI
workspace.returnToPrimary sessionId、expectedRevision、operationId 核实主空间后走同一 switch;不猜测 cwd 或默认分支
workspace.inspectCleanup workspaceId 阻塞项、成果/引用/活动检查摘要和短期检查版本;不是删除授权
workspace.cleanup workspaceId、检查版本、operationId、明确清理意图 删除副本的实际结果;执行前重新核实,不默认删分支
activity.list/status 当前会话范围、可选 activityId 受授权活动、状态来源、观测时间与覆盖范围
activity.readLogs activityId、游标、大小上限 分页日志,不借路径参数读任意文件
activity.stop activityId、operationId 停止已受理或终态;受理不等于已结束

工具由宿主重新校验会话、项目关联、环境能力、空间身份、路径冲突与权限。工具请求不能通过伪造 sessionId 或任意 PID 扩大范围;同一项目不自动获得其他会话活动的控制权。已明确授权管理的共享活动才可访问。

错误至少区分:STALE_BINDING、TARGET_UNAVAILABLE、WORKSPACE_IDENTITY_CHANGED、FOREGROUND_BUSY、PENDING_APPROVAL、CONTROLLER_RETENTION_REQUIRED、TRACKING_UNKNOWN、UNRESOLVED_CHANGES、OTHER_REFERENCES、RECONCILE_REQUIRED。错误带真实阶段、可恢复动作和已产生副作用,不以“操作失败”掩盖已创建目录,也不自动重试未知副作用。

重复 operationId 查询/返回原操作结果,不重复创建 worktree、发消息或停止无关活动。未完成记录先对账;不同参数复用同一 ID 应拒绝。

6. 切换状态机与 Run 边界

6.1 首期保守路径

首期选用同一会话内透明续接新 Run,不假定 SDK 在现有 Run 内可靠改变 cwd。 SDK 技术验证若证明安全的执行片段方案,再单独评审;不把它作为首期交付的隐藏前提。

请求切换
 → 锁定会话调度并核对 binding revision
 → 等待前台工具到安全边界 / 明确取消且确认终止
 → 核实目标、权限、旧 controller 可保留性
 → 准备新执行上下文与操作日志
 → 原子提交绑定和续接意图
 → 在原会话建立引用新快照的新 Run
 → 核实实际执行目录后放行后续工具

agent 调用切换工具时,该控制调用本身不能被纳入“等待所有前台工具结束”,否则会等待自己形成死锁。宿主先登记切换请求和阻止其他新派发;控制调用在旧上下文中恰好返回一次“已受理、待边界提交”,随后在可验证的工具边界执行提交与续接。受理不冒充切换成功,最终结果由 operationId 关联的宿主事件报告。旧 SDK 在控制工具响应入账前不得销毁;如何捕获这个边界属于阶段 A 的必验项。

用户无需点“结束 Run”。宿主负责边界、旧调用结果入账和透明续接;技术上的旧 Run 收敛不等于结束产品任务。不能假定所有 SDK 工具绝对串行:前台调用、已知并发调用、待处理授权都纳入调度检查,后台活动另行管理。

续接不得重复追加用户消息、重复工具结果或重新执行已完成工具。旧 Run 记为受控交接而不是伪造一次任务成功;新 Run 引用 continuationOfRunId,保留前后因果。新模型/权限的解析继续遵守现有消息快照规则,空间切换不变相提升权限。

关键门禁:如果关闭旧 SDK controller 会丢失仍运行的任务状态/stopTask 能力,保留旧 controller 直到其受管任务结束,或阻止本次切换并说明需先停止哪些活动。不能为“切换成功”关闭 controller,再把旧活动标记完成。宿主直接管理的进程可以独立于 Run/controller 生命周期,但必须验证这种独立性。

提交成功但新 Run 启动失败时,绑定保留已提交事实、会话暂停并报告失败,或通过新的受控操作回到原有效空间;不能后台偷偷回滚而让日志/UI 矛盾。只有新上下文已验证,才允许后续执行。

6.2 队列和待处理授权

  • 每条队列消息入队捕获 workspaceId 和 bindingRevision,权限快照保持现有语义。
  • 切换成功后,尚未派发且 revision 不匹配的消息进入 blocked-workspace-change;不自动移到新空间、不悄悄留在旧空间执行。
  • 用户或拥有本会话管理能力的 agent 可明确选择重新绑定到已验证空间、保留旧目标待以后恢复,或取消。重新绑定产生审计事件和新的目标修订,不放宽原权限,不把旧已派发消息改成新消息。
  • 外部删除触发自动回退也遵守上述规则:当前会话回主空间,不代表旧队列自动在主空间执行。
  • 第一期有待处理授权时先阻断切换,允许用户完成/拒绝或显式取消旧请求;确认取消后再切换。不得把“允许”按钮的回调应用到另一个 Run/cwd。
  • 异常删除或恢复使旧授权失去执行上下文时,旧请求失效,取消其尚未执行的调用。新 Run 真要执行相应动作,重新评估并重新请求授权,不能沿用一次性旧同意。
  • 迟到的授权回复必须用 requestId、runId、workspaceId/revision 校验并拒绝过期结果;消息选择问答也不得驱动已失效的旧 Run。

6.3 原子性与故障恢复

不把 Git 创建目录、写存储和 SDK 启动假装成一笔可回滚数据库事务。使用最小持久化操作日志,加会话/空间锁和修订号校验;原子替换绑定记录时同时保留 operationId,跨文件结果通过日志对账。

中断位置 恢复规则
创建前失败 保留原绑定,记录失败
Git 创建成功,登记或切换失败 保留新副本,报告其路径和未接管/待恢复状态,不擅自删除
prepared 未 committed 核实真实目录与 controller,再选择继续或终止;不能仅凭日志声称完成
committed 后未确认新 Run 保留已提交事实,禁止自动重放,恢复调度或标记 reconcile-required
进程/任务状态无法核实 活动为 unknown,阻止相关清理;不重复启动可能仍活着的命令
清理时崩溃 对比 Git worktree 元数据、目录、登记与历史引用,记录实际残留,不自动 force/prune

重启后未完成 Run、活动和操作先进入对账;原子 rename/日志仅改善一致性,不是跨进程无条件成功保证。任何恢复都不回滚已经发生的文件写入、发布或外部副作用。

7. 后台活动的真实生命周期

宿主统一 Activity Registry 作为 UI 和 agent 的事实来源。SDK 任务、宿主进程、PTY shell 使用各自 adapter,保留观测来源和覆盖范围,不把所有“工具调用成功”转换成“进程退出”。

starting → running → exited / failed
    └────→ failed
starting / running → stopping → stopped(有退出确认)
任意非终态 → unknown(断连、失去身份或跟踪)
unknown → 经可信对账恢复 running / stopping / 明确终态

自然退出与用户请求停止分开;收到停止请求只进入 stopping。停止超时保留 stopping 或 unknown,不移除活动。重复事件、乱序通知按 controllerId/taskId、SDK 的任务执行 run_id(如有)及实例代次、事件顺序/已核实终态归并,不能让旧 incarnation 的迟到进度覆盖新执行或退出结果。SDK 版本缺少足够执行身份、无法区分 resume/复用时转 unknown/对账,不能猜测合并。就绪探测是可选端口/健康检测,必须属于本活动且有明确目标,不因端口被其他程序占用就认定本服务 ready。

进程控制要求:

  • 保存受管启动关系、句柄/启动身份,避免 PID 复用导致结束其他进程;代理端只接受 activityId。
  • 停止 agent 不证明它的子进程退出;分别核实受管后代。宿主管理进程应验证 Windows 与其他目标平台的进程树策略。
  • SDK background task 列表是该 controller 的任务快照,重启后空列表不能证明旧进程不存在。SDK-only coverage 不自动提升为 owned-tree。
  • PTY shell 退出不证明其中所有命令退出。任意手输 shell 命令或脱离父进程的后台命令,要么通过受控启动协议纳管,要么明确其覆盖未知;不得靠日志猜测进程身份。
  • 第一阶段覆盖宿主受管启动和经验证的 SDK task,禁止承诺“知道系统所有命令”。未覆盖的 YCode 启动方式会阻止其空间自动清理,而不是扫描外部命令补齐。
  • 会话切换后旧活动继续显示来源空间;新空间启动同类服务仍可能有端口、数据库、凭据和共享 Git 状态冲突,worktree 不是完整运行隔离。

8. UI 落点与不变项

▼ YCode
  日常开发                  主空间
  开发登录功能              登录空间
  修复加载问题              修复空间

后台活动 2(可折叠)
[子 agent] 审查登录实现  运行中  登录空间  [详情] [结束]
[进程]     pnpm dev     已就绪  主空间    [日志] [结束]
─────────────────────────────────────────────
原输入区域 / 独占的授权或问答区域

新增独立 activitySlot,沿用原有间距、字体和样式变量,不新增复杂导航。活动多时折叠计数,详情和日志按需打开;退出活动保留可查记录,不无限占用输入区。

活动条与 floatingSurface、queueSlot、approvalSlot 分开:授权/选择卡独占输入区时,普通输入框仍隐藏;紧凑活动条可以保留,但不能遮挡选项或让输入框重新出现。发消息、整轮停止、队列和授权状态机不因活动条改变。单活动结束调用 activity.stop,不调用现有取消整个 Run 的 onStop。

侧栏任务 ID 与选中项不因切换改变,仅更新当前空间的轻量标记。活动显示启动空间,历史工具显示执行空间,不能都读取当前绑定渲染。正常切换无需额外长提示;阻塞、未知状态和失败必须在已有反馈位置明确说明。

9. 外部删除与清理门禁

打开会话、发消息、派发工具前校验空间,文件通知只做提前提示。确认删除需结合环境在线可访问、路径身份与 Git worktree 信息;目录暂时不可访问、权限错误、超时只能 unavailable/unknown。目录存在但被替换为另一仓库属于 identity-changed,不静默接管。

确认删除 → 阻止旧空间派发 → 收敛旧前台结果/停止状态 → 核实已登记主空间身份与权限 → 同一会话按切换事务自动回退 → 检查主空间现状再继续。旧后台活动仍保留可控;旧队列阻塞,旧授权失效;未知写入/发布不自动重放。主空间无效时暂停,不能随意选择全局空间。

清理只接受明确清理意图,使用空间级排他门禁阻止新受管执行,并在真正删除前重新校验:

  1. 该空间的前台、后台、子 agent 及受管后代已确认终态,无 unknown 或覆盖缺口。
  2. 未提交修改和未跟踪文件已有明确保全/处理结果;目录干净不是合并证明。
  3. 未合并提交已有明确交付保全证据;合并路径须先确认目标分支合并成功,再清理,不能把清理操作变成隐式 merge。PR/补丁路径核实保全策略,不伪称已合并。
  4. 其他任务/会话引用已显式处置;创建者不能越过其他使用者。历史引用保留,不是阻止所有清理的永久活动锁。
  5. 需要返回的当前会话有有效主空间;当前绑定已迁移或在同一受控操作中完成迁移。
  6. 删除前核对空间身份、检查版本和无新增调用,确保没有检查后又启动活动的竞态。

默认不 force 删除、不级联删分支、不删除历史。已有旧活动允许先切回主空间,但标记清理受阻。删除失败保留登记/残留状态,不宣称已完成。没有成果证据的外部删除只记异常与损失风险,不能记为成功交付。

10. 迁移与分阶段实施门禁

既有会话按已保存 workspaceId/cwd 迁移绑定,不能一律绑定当前全局空间。cwd 与登记不匹配时核对身份,无法核实则不可用;保留原始值供恢复。既有 Run 无可靠快照时标记历史来源未知,不回填一个“看起来正确”的空间。首期环境登记 local,不提前实现远程连接。备份/迁移版本与回退兼容策略随实际存储改动评审。

阶段 交付范围 进入下一阶段的门禁
A 技术验证 SDK 0.3.304 cwd/resume/工具边界;task 生命周期;controller 保留;Windows 受管进程身份与停止 记录真实可行路径及不支持项。若不能保留旧活动控制,采用切换阻断,不以 mock 通过替代
B 核心绑定 最小类型、不可变快照、会话绑定、操作日志、队列/授权校验、创建/切换/返回 同一会话新 Run 真实 cwd 生效;故障与重复操作不重放、不误路由
C 活动管理 注册表、SDK/进程 adapter、按活动查询/日志/停止、controller 生命周期 旧空间活动仍可管;终态可信;身份复用、重启未知、越权均正确处理
D UI 集成 简单侧栏、独立活动条、轻量空间标记、单活动结束 授权/问答独占和原发消息/回合状态不回归,无额外导航树
E 恢复与清理 确认删除回退、空间锁、成果/引用/覆盖门禁、迁移 故障注入和 Windows 真实验收通过,才开放受管自动清理

A 可用隔离 spike 验证而不改产品默认行为;后续分阶段交付不将未完成的能力暴露成成功按钮。新能力保留回退开关,关闭时不销毁已登记活动或历史;正在运行的活动仍须可观察和停止。

11. 验收清单与证据要求

场景 必须断言 验证层级
创建并继续/仅创建 前者登记并切换原会话,后者不改变绑定;不重复建目录 宿主集成 + 真实 Git
当前绑定切换 新 Run 实际 cwd/仓库身份正确,旧 Run 快照不变 真实 SDK,不只 mock
工具边界续接 旧工具仅执行一次,结果仅记一次,新工具进入新空间 mock 故障注入 + 真实 SDK
排队与授权 旧 revision 阻塞、重新绑定显式;迟到允许失效,新空间重新评估 状态测试 + UI
旧后台活动 切换后仍显示旧空间、可查询/停止;关闭 controller 不丢管理 SDK/宿主真实进程
存活/就绪/停止 活着未 ready、stop 请求未退出、超时 unknown 均不伪终态 受控长驻程序 + 平台测试
PID/身份与权限 PID 复用不误杀,任意 PID/其他会话活动操作被拒 adapter 单测 + 平台集成
外部删除/不可用 确认删除才回退;离线/权限错误不回退;主空间无效暂停 文件/Git 集成 + 故障注入
崩溃恢复 prepared/committed/删除中断均对账,不重放副作用、不假完成 持久化故障注入
清理门禁 脏文件、未跟踪文件、未保全提交、其他引用、unknown 均阻断 真实 Git fixture
单活动结束 仅停止指定受管活动,不取消整轮或触及外部命令 UI + 宿主集成
布局回归 授权/问答时不显示普通输入框,队列/活动互不遮挡,侧栏不增层 YCode 截图/交互验收
迁移 原 cwd 保留,不匹配与旧历史未知如实呈现 存储 fixture

真实 SDK、真实 Windows 进程与真实 UI 验收必须分别记录环境、版本、命令/操作和结果;mock 或类型检查不能证明 cwd 重绑定与进程树管理可靠。本文仅提交设计文档,未运行上述产品验收、未改动业务源码,后续交付必须逐项给出实际证据和仍未覆盖的范围。