[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M7DBP6T40RB403W7VADV2RAZ":3,"skill-same:01M7DBP6T40RB403W7VADV2RAZ":48},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":18,"publishedAt":19,"linkOnly":20,"markdownContent":21,"markdownBody":22,"frontMatter":23,"refName":24,"commitSha":25,"skillDirectory":26,"forksCount":27,"repositoryHtmlUrl":28,"repositoryHomepageUrl":29,"ownerHtmlUrl":30,"ownerBlogUrl":31,"ownerDescription":32,"updatedAt":33,"install":34,"resources":47},"01M7DBP6T40RB403W7VADV2RAZ","session-management",null,"修改 ZCode 会话管理（左侧任务列表、tasks-index.sqlite、sessions-index、CLI session store、标题\u002F状态\u002F置顶\u002F归档\u002F未读\u002F删除、虚拟项目与 roots、workspace 身份、相关 migration）之前必读。它把 2026-09 「虚拟项目与数据归属收口」重构及分组恢复的设计理由、历史 bug 根因与不变量蒸馏成检查清单，让后来者知道为什么这样设计、哪些线不能踩。","ZCodium-project\u002FZCodium","ZCodium-project","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F331969751?v=4","01M7DBKVDM2CY9G27NC8F39MCG","ZCodium","01M7DBKVEPNTJN0R8FNRV88JEH",253,"MIT","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fsession-management\u002FSKILL.md",[],[],"2026-11-15 14:19:17",false,"---\nname: session-management\ndescription: 修改 ZCode 会话管理（左侧任务列表、tasks-index.sqlite、sessions-index、CLI session store、标题\u002F状态\u002F置顶\u002F归档\u002F未读\u002F删除、虚拟项目与 roots、workspace 身份、相关 migration）之前必读。它把 2026-09 「虚拟项目与数据归属收口」重构及分组恢复的设计理由、历史 bug 根因与不变量蒸馏成检查清单，让后来者知道为什么这样设计、哪些线不能踩。\n---\n\n# Session 管理设计蒸馏\n\n改动范围命中下列任一项时使用本 skill：`packages\u002Fservices\u002Fsrc\u002Fsession\u002FtaskIndexRepo.ts`、`packages\u002Fservices\u002Fsrc\u002Fzcode-agent\u002FzcodeTaskIndexSyncer.ts`、`zcodeTaskServiceAdapter.ts`、`packages\u002Fui` 侧栏 \u002F 任务列表 \u002F 项目树、`apps\u002Fzcode-cli\u002Fpackages\u002Fadapters\u002Fsrc\u002Fstorage\u002Fsession-store\u002F*`、sessions-index 协议、workspace \u002F project \u002F roots 数据结构、两库 migration。\n\n权威 spec：`docs\u002Fsuperpowers\u002Fspecs\u002F2026-09-09-virtual-project-design.md` 与 `docs\u002Fui\u002Ftask-grouped-view.md`。2026-10-13 分组恢复裁决覆盖历史 Group 合并 Project 方案。本 skill 不重复 spec，只讲「为什么」和「怎么不踩坑」。\n\n## 1. 一句话原则\n\n**会话事实归 CLI，组织态归 Host；每个字段只有一个写者。**\n\n```text\nCLI  db.sqlite      存在性(软删除 time_deleted)、title+title_source、time_created\u002Fupdated、last_outcome、正文、goal、fork、trace\nHost tasks-index    project_id、pinned、archived、unread_at(+CAS)、sort_order、projects\u002Froots\u002Fhosts、定时\u002F闲时；控制端另存跨设备分组成员与顺序\n                    cli_* 列 = CLI 事实的只读镜像，唯一写者 taskIndexSyncer\n禁止：CLI 写 app 库；Host 写 db.sqlite；Host 对任何 cli_* 列写 Date.now() 或从 snapshot 推导的值\n```\n\n### 为什么\n\n重构前 title \u002F status 相关 Bugfix 注释有 30 多处（`rg \"Bugfix\" packages\u002Fservices\u002Fsrc\u002Fzcode-agent\u002FzcodeTaskIndexSyncer.ts packages\u002Fservices\u002Fsrc\u002Fsession\u002FtaskIndexRepo.ts`），几乎全部属于两类：\n\n1. Host 替 CLI 写会话事实：`updated_at = Date.now()`（rename \u002F 状态变更）与 CLI 的 `time_updated` 分叉，导致排序跳动，UI 被迫只信 sessions-index 的 `lastActivityAt`；rename 先写本地再 best-effort 通知 CLI，失败只 warn，两边「是否手动标题」不一致；`task_status` 从 snapshot 反推，冷启动恒为 completed，残留 running 只能靠 UI 规则吸收。\n2. CLI 替 Host 决定行集合：3.4.0 曾因 sessions-index 快照缺 summary 导致历史任务在 Grouped 视图消失（`docs\u002Fsuperpowers\u002Fspecs\u002F2026-07-20-sidebar-task-row-authority-design.md`）；CLI 冷种子会复活 app 已删的 session，app 只能靠 tombstone 压制。\n\n结论：不是「哪个库更好」，而是「谁第一手知道这个事实」。会话发生了什么只有 CLI 知道；用户对列表做了什么只有 Host\u002FUI 知道；CLI 是每 workspace 一进程且可不在线，跨 workspace 的列表必须有 Host 侧落盘（`onDynamicWorkspaceEvent` 注释明确禁止为列表拉起 Agent）。\n\n## 2. 不变量（改代码前逐条对照）\n\n| #   | 不变量                                                                                                                                                                      | 违反时的典型症状                                                    |\n| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |\n| I1  | `workspaceKey = workspaceIdentity?.trim() \\|\\| workspacePath` 只表达身份隔离；执行路径永远用 `workspacePath` \u002F `root_path`                                                  | 远程 identity 被写进 cwd（3.4.2 事故）                              |\n| I2  | session 绑定目录（cwd）创建后永不变；项目移动只改 `project_id`，分组移动只改成员与顺序                                                                                      | 冷启动后 provider \u002F memory \u002F permissions 找不到                     |\n| I3  | 项目其余 roots 只作为 `additionalDirectories` 供 skills \u002F commands \u002F subagents \u002F 可写范围；AGENTS.md、settings、MCP、hooks、plugins、memory、permissions 只按绑定目录链解析 | 另一目录的可执行配置混进当前会话；同名 MCP\u002Fhook 冲突                |\n| I4  | CLI 不感知项目；协议里只有目录列表                                                                                                                                          | CLI 出现 project 概念 = 设计漂移                                    |\n| I5  | 行集合由 app 库决定，sessions-index 只补实时字段（phase、lastActivityAt、pending interaction）                                                                              | 任务在列表里消失 \u002F 复活                                             |\n| I6  | 排序时间只取 CLI 创建\u002F活动时间镜像；沿用 running\u002Fprewarming 优先、运行层创建时间稳定排序及普通层创建\u002F更新时间偏好；pin \u002F archive \u002F rename \u002F 未读不改时间                    | 重命名后跳到顶部                                                    |\n| I7  | 未读用 CAS（`expectedUnreadAt`），只有 Host 显式 `unreadSignal` 才制造未读                                                                                                  | 手机已读被桌面覆盖；每轮完成全表闪烁                                |\n| I8  | 标题优先级：用户 override(`title_source=custom`) > 模型生成 > 首条 prompt > 占位 \"New session\"；快照永不覆盖 override                                                       | 手动标题闪回                                                        |\n| I9  | 删除 = CLI 软删除（`time_deleted`），app `deleted` 是镜像；冷种子 \u002F listSessions \u002F TUI 必须过滤                                                                             | 已删 session 复活                                                   |\n| I10 | 两库 schema 只加不删不改旧列语义；新列可空或带默认；`ON CONFLICT(workspace_key, task_id)` 的唯一约束必须保留                                                                | 降级后旧版本崩溃                                                    |\n| I11 | 派生目录 hash（`sessions\u002F{hash}`、`agent-config\u002F{provider}\u002F{hash}`、CLI memory）输入是真实目录 + identity，与项目无关，不迁移                                               | 升级后配置 \u002F 记忆丢失                                               |\n| I12 | 手机远控 bridge \u002F queue \u002F snapshot key 只用 workspaceKey；桌面 continuous 与手机 replayable 边界不变                                                                        | 远控串会话                                                          |\n| I13 | Host 组织态只存在原列，不做副本；旧列 `deleted` \u002F `title_overridden` 是「待交接给 CLI 的意图」，每次启动全表对账，不能只补 NULL                                             | 降级期删除 \u002F 重命名在再升级后丢失                                   |\n| I14 | sessions-index snapshot 缺席不等于删除；删除只能来自 `session.removed` 或 `sessionsIndex\u002Freconcile` 返回 deleted                                                            | 事件丢失后任务复活或误删                                            |\n| I15 | 恢复 CLI 库备份必须关闭外键并校验行数 \u002F 哈希；`message`\u002F`part` 对 `session` 是 ON DELETE CASCADE，裸 DELETE 会清空正文                                                      | 恢复后消息全丢                                                      |\n| I16 | 附加目录由 Host 统一解析并贯穿 create \u002F 显式 resume \u002F V4 subscribe 冷恢复；排除的是 session cwd 不是主要目录；运行实例存在时不刷新                                          | 桌面打开历史任务拿不到附加目录；换主要目录后老会话目录范围错乱      |\n| I17 | 空归属 session 只在首次发现时判定一次归位（bit 8）；不自动建项目；不归入者在任务区、时间线或分组中可见。app 行缺失 = 未归类 `[]`，项目缺失 \u002F 读取失败 = 显式报错            | 已移除的 workspace 复活；会话后来被悄悄挪进项目；TUI 新建会话打不开 |\n\n## 3. 关键裁决速查（详见 spec 第 3 节）\n\n- 2026-10-10 远程裁决：本地\u002F远程项目平铺，Host 不作为分组；远程先建单目录项目再建会话，不允许无项目创建或拖拽追加目录。统一项目顺序归控制端侧栏偏好。详见 `docs\u002Fsuperpowers\u002Fspecs\u002F2026-10-10-session-manage-upstream-integration.md`。\n- 侧栏 = 全局置顶区（session + 置顶项目）→ 项目区 → 任务区（`project_id IS NULL`，任意 cwd）；`~\u002F.zcode\u002Fworkspace\u002F*` 只作为全局新建任务的默认执行目录。筛选含按项目 \u002F 按分组 \u002F 最近更新；真实目录不是节点，不恢复旧两级切换器。\n- 项目：本地 0..n 个同 host 的 roots + 一个主要目录，远程恰好一个固定目录；同一目录可属多个项目；新建 session cwd = 主要目录；仅本地 0 root 时自动建 `~\u002F.zcode\u002Fworkspace\u002F\u003Cts>` 并加为主要 root。\n- 本地项目及在线远端权威项目删除 = 软删除容器，session 保留归属，时间线可见；新建 roots 集合完全相等的项目时提示恢复；不提供彻底删除。远程项目离线删除只移除本机入口与缓存，不触发远端软删除或恢复。\n- 本地项目移除 root \u002F 换主要目录不影响已创建 session、定时任务、闲时任务、Bots（它们在创建时固化 cwd 与附加目录）；roots 变更对运行中 session 下次 resume 生效。\n- 同名 skill \u002F subagent 来自不同 root 时并存，由 CLI 赋限定名 `\u003CrootName>\u002F\u003Cname>`。\n- 分组：控制端 Host 唯一持有跨设备分组，手机复用该 Host；不按 workspace 建组，不将分组转换为项目。分组不改变 cwd、项目、CLI 时间、配置或权限。读取只读，单节点移动在事务内复检来源\u002F锚点，缺席不删除；系统任务只首次归组，手工移出后不拉回。\n- 展示偏好：有效新版 view 优先，否则沿用旧 organizeBy；旧 grouped 默认进入按分组。新建任务固化 draft 的分组 placement，首次发送后幂等提交，不在导航时猜测。\n- 远程：项目与任务组织态留在远端 app 库；本机持久化 host 连接记录、用户已添加的项目入口及基础信息缓存。离线不可展开、改名或编辑 roots，项目操作仅允许移除本机入口与缓存，远端项目与会话保留，无待同步删除队列。远程只允许创建时确定的一个固定 root，host 上限 20，启动自动连接已保存 host。\n- 重连只刷新本机仍存在的入口，迟到响应不得 upsert 已移除入口；setting.json 从本机入口列表派生，不反向重建已移除入口。重新添加远程项目须由用户主动选择，或由在线创建成功显式添加；删除本机 host 只移除连接及所属入口。\n- 设置页 agent 配置管理按真实目录（roots 去重平铺）；定时 \u002F 闲时 \u002F Bots 选虚拟项目。\n\n## 4. 数据与迁移纪律\n\n- 版本化 migration runner 两库共用（抽自 `apps\u002Fzcode-cli\u002F...\u002Fsession-store\u002Fmigration-runner.ts`）：`schema_migration(id, checksum, app_version)`，checksum 不可变，未知 id 忽略。\n- 每条 migration 显式声明 `touchedTables`；runner 在同一读事务里只备份这些表（`ATTACH + CREATE TABLE AS SELECT`）；备份只为迁移失败恢复，正常流程只产生不消费，不做整库快照（本机整库 770MB vs 表级 16MB）。\n- 每条 migration 一个单测：fixture 前后对全部表做内容哈希，只允许 `touchedTables` 变化。`schema.baseline.sql` 由 CI 做只增 diff。\n- 兼容退场三阶段：V1 只读新列、旧列只写不读；V2 写 `schema_floor` 并停双写；V3 物理删退场列 \u002F `time_archived` 并重建主键。分组表已恢复为运行态，不能按旧计划删除。不要在任何阶段引入「永久」兼容分支。\n- 降级靠加法 schema，不靠备份；首次迁移遗留、旧版本新增或 CLI 首次发现的未归属 session 只判定一次：目录唯一匹配同 host 下未删除项目才归入，零个或多个匹配保留 NULL 并进入任务区，不自动建项目。唯一例外是远端 Source Server 的首次迁移：远端自身没有旧 workspace 清单，按历史任务目录建单 root 项目（虚拟项目 spec 2026-10-15 裁决）。旧 group、空组、系统组、颜色、成员和顺序继续读取；旧 Group → Project 转换取消，workspace → Project 保留。\n- `project_id IS NULL` 是合法未归类状态，不是待迁移标记。启动时先识别 `host_id IS NULL` 的旧版本新增行，再在同一事务补齐身份与首次归属；新版本创建或首次插入行时原子写入身份和归属。已处理的 NULL 行不因启动、对账或新增同目录项目而自动归入；全局新建任务显式保持未归类。\n- 迁移复用同一 SQL \u002F Repo，启动门禁在 Host Worker 完成后才初始化业务服务；异步等待锁，迁移事务提交后再发布 ready，失败 fail-closed（重试 \u002F 打开备份目录）。不得另造迁移实现。\n\n## 5. 改动前检查清单\n\n1. 这个字段的**唯一写者**是谁？如果你要在另一侧写它，先回到第 1 节重新判断，通常应改为发命令（`renameSession` \u002F `deleteSession`）再等镜像。\n2. 你写入的时间戳来自 CLI 事件还是 `Date.now()`？后者只允许写 Host 组织态自己的时间列（`pinned_at`、`meta_updated_at`），不允许进任何排序依据。\n3. 是否会让 sessions-index 决定行的存在或消失？不允许。\n4. 是否用 `workspacePath` 做了身份判等或建 key？远程必须带 `workspaceIdentity`。\n5. 新增列 \u002F 表是否可空或带默认、是否更新了 `schema.baseline.sql` 与 migration 的 `touchedTables`、是否有逐表哈希单测？\n6. 改了 CLI 配置发现逻辑？只允许在 skills \u002F subagents \u002F 路径策略三处消费 `additionalDirectories`；其余保持只按 `workingDirectory`。\n7. 涉及标题 \u002F 状态 \u002F 未读 \u002F 归档 \u002F 删除的行为变化，e2e 是否覆盖了「桌面 + 手机远控」「本地 + SSH\u002FWSL」两组交叉？\n8. 涉及 schema 的改动，是否跑过「旧 fixture 升级 → 旧代码路径读写（含修改既有行：删除、重命名）→ 再升级」的 e2e？\n9. 触碰删除 \u002F 标题的代码，是否保持了「意图位 → 惰性交接 → 镜像回写」三段，以及 orphan 的处理？\n\n## 6. 参考实现与文档\n\n- 现状事实：`docs\u002Ftask\u002Ftask-sqlite-index.md`、`docs\u002Fv4-refactor\u002F14-sessions-index.md`、`docs\u002Fui\u002Ftask-title-authority.md`、`docs\u002Fui\u002Ftask-unread-state.md`、`docs\u002Ftask-list-refresh-semantics.md`、`docs\u002Fwsl-task-status-inconsistency.md`（订阅被静默替换的根因）。\n- 历史决策：`docs\u002Fsuperpowers\u002Fspecs\u002F2026-07-13-v4-sidebar-task-state-authority-design.md`、`2026-07-20-sidebar-task-row-authority-design.md`、`docs\u002Flocal-workspace-path-cold-resume-identity.md`。\n- 当前分组与视图：`docs\u002Fui\u002Ftask-grouped-view.md`、`docs\u002Fui\u002Fsidebar-task-view-switcher.md`。\n- 已废弃（保留仅供降级理解）：`docs\u002Fgrouped-task-workspace-bootstrap.md`、`apps\u002Fzcode-cli\u002Fdocs\u002Fdesign\u002Fv2\u002Fmulti-workspace.md`。\n","# Session 管理设计蒸馏\n\n改动范围命中下列任一项时使用本 skill：`packages\u002Fservices\u002Fsrc\u002Fsession\u002FtaskIndexRepo.ts`、`packages\u002Fservices\u002Fsrc\u002Fzcode-agent\u002FzcodeTaskIndexSyncer.ts`、`zcodeTaskServiceAdapter.ts`、`packages\u002Fui` 侧栏 \u002F 任务列表 \u002F 项目树、`apps\u002Fzcode-cli\u002Fpackages\u002Fadapters\u002Fsrc\u002Fstorage\u002Fsession-store\u002F*`、sessions-index 协议、workspace \u002F project \u002F roots 数据结构、两库 migration。\n\n权威 spec：`docs\u002Fsuperpowers\u002Fspecs\u002F2026-09-09-virtual-project-design.md` 与 `docs\u002Fui\u002Ftask-grouped-view.md`。2026-10-13 分组恢复裁决覆盖历史 Group 合并 Project 方案。本 skill 不重复 spec，只讲「为什么」和「怎么不踩坑」。\n\n## 1. 一句话原则\n\n**会话事实归 CLI，组织态归 Host；每个字段只有一个写者。**\n\n```text\nCLI  db.sqlite      存在性(软删除 time_deleted)、title+title_source、time_created\u002Fupdated、last_outcome、正文、goal、fork、trace\nHost tasks-index    project_id、pinned、archived、unread_at(+CAS)、sort_order、projects\u002Froots\u002Fhosts、定时\u002F闲时；控制端另存跨设备分组成员与顺序\n                    cli_* 列 = CLI 事实的只读镜像，唯一写者 taskIndexSyncer\n禁止：CLI 写 app 库；Host 写 db.sqlite；Host 对任何 cli_* 列写 Date.now() 或从 snapshot 推导的值\n```\n\n### 为什么\n\n重构前 title \u002F status 相关 Bugfix 注释有 30 多处（`rg \"Bugfix\" packages\u002Fservices\u002Fsrc\u002Fzcode-agent\u002FzcodeTaskIndexSyncer.ts packages\u002Fservices\u002Fsrc\u002Fsession\u002FtaskIndexRepo.ts`），几乎全部属于两类：\n\n1. Host 替 CLI 写会话事实：`updated_at = Date.now()`（rename \u002F 状态变更）与 CLI 的 `time_updated` 分叉，导致排序跳动，UI 被迫只信 sessions-index 的 `lastActivityAt`；rename 先写本地再 best-effort 通知 CLI，失败只 warn，两边「是否手动标题」不一致；`task_status` 从 snapshot 反推，冷启动恒为 completed，残留 running 只能靠 UI 规则吸收。\n2. CLI 替 Host 决定行集合：3.4.0 曾因 sessions-index 快照缺 summary 导致历史任务在 Grouped 视图消失（`docs\u002Fsuperpowers\u002Fspecs\u002F2026-07-20-sidebar-task-row-authority-design.md`）；CLI 冷种子会复活 app 已删的 session，app 只能靠 tombstone 压制。\n\n结论：不是「哪个库更好」，而是「谁第一手知道这个事实」。会话发生了什么只有 CLI 知道；用户对列表做了什么只有 Host\u002FUI 知道；CLI 是每 workspace 一进程且可不在线，跨 workspace 的列表必须有 Host 侧落盘（`onDynamicWorkspaceEvent` 注释明确禁止为列表拉起 Agent）。\n\n## 2. 不变量（改代码前逐条对照）\n\n| #   | 不变量                                                                                                                                                                      | 违反时的典型症状                                                    |\n| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |\n| I1  | `workspaceKey = workspaceIdentity?.trim() \\|\\| workspacePath` 只表达身份隔离；执行路径永远用 `workspacePath` \u002F `root_path`                                                  | 远程 identity 被写进 cwd（3.4.2 事故）                              |\n| I2  | session 绑定目录（cwd）创建后永不变；项目移动只改 `project_id`，分组移动只改成员与顺序                                                                                      | 冷启动后 provider \u002F memory \u002F permissions 找不到                     |\n| I3  | 项目其余 roots 只作为 `additionalDirectories` 供 skills \u002F commands \u002F subagents \u002F 可写范围；AGENTS.md、settings、MCP、hooks、plugins、memory、permissions 只按绑定目录链解析 | 另一目录的可执行配置混进当前会话；同名 MCP\u002Fhook 冲突                |\n| I4  | CLI 不感知项目；协议里只有目录列表                                                                                                                                          | CLI 出现 project 概念 = 设计漂移                                    |\n| I5  | 行集合由 app 库决定，sessions-index 只补实时字段（phase、lastActivityAt、pending interaction）                                                                              | 任务在列表里消失 \u002F 复活                                             |\n| I6  | 排序时间只取 CLI 创建\u002F活动时间镜像；沿用 running\u002Fprewarming 优先、运行层创建时间稳定排序及普通层创建\u002F更新时间偏好；pin \u002F archive \u002F rename \u002F 未读不改时间                    | 重命名后跳到顶部                                                    |\n| I7  | 未读用 CAS（`expectedUnreadAt`），只有 Host 显式 `unreadSignal` 才制造未读                                                                                                  | 手机已读被桌面覆盖；每轮完成全表闪烁                                |\n| I8  | 标题优先级：用户 override(`title_source=custom`) > 模型生成 > 首条 prompt > 占位 \"New session\"；快照永不覆盖 override                                                       | 手动标题闪回                                                        |\n| I9  | 删除 = CLI 软删除（`time_deleted`），app `deleted` 是镜像；冷种子 \u002F listSessions \u002F TUI 必须过滤                                                                             | 已删 session 复活                                                   |\n| I10 | 两库 schema 只加不删不改旧列语义；新列可空或带默认；`ON CONFLICT(workspace_key, task_id)` 的唯一约束必须保留                                                                | 降级后旧版本崩溃                                                    |\n| I11 | 派生目录 hash（`sessions\u002F{hash}`、`agent-config\u002F{provider}\u002F{hash}`、CLI memory）输入是真实目录 + identity，与项目无关，不迁移                                               | 升级后配置 \u002F 记忆丢失                                               |\n| I12 | 手机远控 bridge \u002F queue \u002F snapshot key 只用 workspaceKey；桌面 continuous 与手机 replayable 边界不变                                                                        | 远控串会话                                                          |\n| I13 | Host 组织态只存在原列，不做副本；旧列 `deleted` \u002F `title_overridden` 是「待交接给 CLI 的意图」，每次启动全表对账，不能只补 NULL                                             | 降级期删除 \u002F 重命名在再升级后丢失                                   |\n| I14 | sessions-index snapshot 缺席不等于删除；删除只能来自 `session.removed` 或 `sessionsIndex\u002Freconcile` 返回 deleted                                                            | 事件丢失后任务复活或误删                                            |\n| I15 | 恢复 CLI 库备份必须关闭外键并校验行数 \u002F 哈希；`message`\u002F`part` 对 `session` 是 ON DELETE CASCADE，裸 DELETE 会清空正文                                                      | 恢复后消息全丢                                                      |\n| I16 | 附加目录由 Host 统一解析并贯穿 create \u002F 显式 resume \u002F V4 subscribe 冷恢复；排除的是 session cwd 不是主要目录；运行实例存在时不刷新                                          | 桌面打开历史任务拿不到附加目录；换主要目录后老会话目录范围错乱      |\n| I17 | 空归属 session 只在首次发现时判定一次归位（bit 8）；不自动建项目；不归入者在任务区、时间线或分组中可见。app 行缺失 = 未归类 `[]`，项目缺失 \u002F 读取失败 = 显式报错            | 已移除的 workspace 复活；会话后来被悄悄挪进项目；TUI 新建会话打不开 |\n\n## 3. 关键裁决速查（详见 spec 第 3 节）\n\n- 2026-10-10 远程裁决：本地\u002F远程项目平铺，Host 不作为分组；远程先建单目录项目再建会话，不允许无项目创建或拖拽追加目录。统一项目顺序归控制端侧栏偏好。详见 `docs\u002Fsuperpowers\u002Fspecs\u002F2026-10-10-session-manage-upstream-integration.md`。\n- 侧栏 = 全局置顶区（session + 置顶项目）→ 项目区 → 任务区（`project_id IS NULL`，任意 cwd）；`~\u002F.zcode\u002Fworkspace\u002F*` 只作为全局新建任务的默认执行目录。筛选含按项目 \u002F 按分组 \u002F 最近更新；真实目录不是节点，不恢复旧两级切换器。\n- 项目：本地 0..n 个同 host 的 roots + 一个主要目录，远程恰好一个固定目录；同一目录可属多个项目；新建 session cwd = 主要目录；仅本地 0 root 时自动建 `~\u002F.zcode\u002Fworkspace\u002F\u003Cts>` 并加为主要 root。\n- 本地项目及在线远端权威项目删除 = 软删除容器，session 保留归属，时间线可见；新建 roots 集合完全相等的项目时提示恢复；不提供彻底删除。远程项目离线删除只移除本机入口与缓存，不触发远端软删除或恢复。\n- 本地项目移除 root \u002F 换主要目录不影响已创建 session、定时任务、闲时任务、Bots（它们在创建时固化 cwd 与附加目录）；roots 变更对运行中 session 下次 resume 生效。\n- 同名 skill \u002F subagent 来自不同 root 时并存，由 CLI 赋限定名 `\u003CrootName>\u002F\u003Cname>`。\n- 分组：控制端 Host 唯一持有跨设备分组，手机复用该 Host；不按 workspace 建组，不将分组转换为项目。分组不改变 cwd、项目、CLI 时间、配置或权限。读取只读，单节点移动在事务内复检来源\u002F锚点，缺席不删除；系统任务只首次归组，手工移出后不拉回。\n- 展示偏好：有效新版 view 优先，否则沿用旧 organizeBy；旧 grouped 默认进入按分组。新建任务固化 draft 的分组 placement，首次发送后幂等提交，不在导航时猜测。\n- 远程：项目与任务组织态留在远端 app 库；本机持久化 host 连接记录、用户已添加的项目入口及基础信息缓存。离线不可展开、改名或编辑 roots，项目操作仅允许移除本机入口与缓存，远端项目与会话保留，无待同步删除队列。远程只允许创建时确定的一个固定 root，host 上限 20，启动自动连接已保存 host。\n- 重连只刷新本机仍存在的入口，迟到响应不得 upsert 已移除入口；setting.json 从本机入口列表派生，不反向重建已移除入口。重新添加远程项目须由用户主动选择，或由在线创建成功显式添加；删除本机 host 只移除连接及所属入口。\n- 设置页 agent 配置管理按真实目录（roots 去重平铺）；定时 \u002F 闲时 \u002F Bots 选虚拟项目。\n\n## 4. 数据与迁移纪律\n\n- 版本化 migration runner 两库共用（抽自 `apps\u002Fzcode-cli\u002F...\u002Fsession-store\u002Fmigration-runner.ts`）：`schema_migration(id, checksum, app_version)`，checksum 不可变，未知 id 忽略。\n- 每条 migration 显式声明 `touchedTables`；runner 在同一读事务里只备份这些表（`ATTACH + CREATE TABLE AS SELECT`）；备份只为迁移失败恢复，正常流程只产生不消费，不做整库快照（本机整库 770MB vs 表级 16MB）。\n- 每条 migration 一个单测：fixture 前后对全部表做内容哈希，只允许 `touchedTables` 变化。`schema.baseline.sql` 由 CI 做只增 diff。\n- 兼容退场三阶段：V1 只读新列、旧列只写不读；V2 写 `schema_floor` 并停双写；V3 物理删退场列 \u002F `time_archived` 并重建主键。分组表已恢复为运行态，不能按旧计划删除。不要在任何阶段引入「永久」兼容分支。\n- 降级靠加法 schema，不靠备份；首次迁移遗留、旧版本新增或 CLI 首次发现的未归属 session 只判定一次：目录唯一匹配同 host 下未删除项目才归入，零个或多个匹配保留 NULL 并进入任务区，不自动建项目。唯一例外是远端 Source Server 的首次迁移：远端自身没有旧 workspace 清单，按历史任务目录建单 root 项目（虚拟项目 spec 2026-10-15 裁决）。旧 group、空组、系统组、颜色、成员和顺序继续读取；旧 Group → Project 转换取消，workspace → Project 保留。\n- `project_id IS NULL` 是合法未归类状态，不是待迁移标记。启动时先识别 `host_id IS NULL` 的旧版本新增行，再在同一事务补齐身份与首次归属；新版本创建或首次插入行时原子写入身份和归属。已处理的 NULL 行不因启动、对账或新增同目录项目而自动归入；全局新建任务显式保持未归类。\n- 迁移复用同一 SQL \u002F Repo，启动门禁在 Host Worker 完成后才初始化业务服务；异步等待锁，迁移事务提交后再发布 ready，失败 fail-closed（重试 \u002F 打开备份目录）。不得另造迁移实现。\n\n## 5. 改动前检查清单\n\n1. 这个字段的**唯一写者**是谁？如果你要在另一侧写它，先回到第 1 节重新判断，通常应改为发命令（`renameSession` \u002F `deleteSession`）再等镜像。\n2. 你写入的时间戳来自 CLI 事件还是 `Date.now()`？后者只允许写 Host 组织态自己的时间列（`pinned_at`、`meta_updated_at`），不允许进任何排序依据。\n3. 是否会让 sessions-index 决定行的存在或消失？不允许。\n4. 是否用 `workspacePath` 做了身份判等或建 key？远程必须带 `workspaceIdentity`。\n5. 新增列 \u002F 表是否可空或带默认、是否更新了 `schema.baseline.sql` 与 migration 的 `touchedTables`、是否有逐表哈希单测？\n6. 改了 CLI 配置发现逻辑？只允许在 skills \u002F subagents \u002F 路径策略三处消费 `additionalDirectories`；其余保持只按 `workingDirectory`。\n7. 涉及标题 \u002F 状态 \u002F 未读 \u002F 归档 \u002F 删除的行为变化，e2e 是否覆盖了「桌面 + 手机远控」「本地 + SSH\u002FWSL」两组交叉？\n8. 涉及 schema 的改动，是否跑过「旧 fixture 升级 → 旧代码路径读写（含修改既有行：删除、重命名）→ 再升级」的 e2e？\n9. 触碰删除 \u002F 标题的代码，是否保持了「意图位 → 惰性交接 → 镜像回写」三段，以及 orphan 的处理？\n\n## 6. 参考实现与文档\n\n- 现状事实：`docs\u002Ftask\u002Ftask-sqlite-index.md`、`docs\u002Fv4-refactor\u002F14-sessions-index.md`、`docs\u002Fui\u002Ftask-title-authority.md`、`docs\u002Fui\u002Ftask-unread-state.md`、`docs\u002Ftask-list-refresh-semantics.md`、`docs\u002Fwsl-task-status-inconsistency.md`（订阅被静默替换的根因）。\n- 历史决策：`docs\u002Fsuperpowers\u002Fspecs\u002F2026-07-13-v4-sidebar-task-state-authority-design.md`、`2026-07-20-sidebar-task-row-authority-design.md`、`docs\u002Flocal-workspace-path-cold-resume-identity.md`。\n- 当前分组与视图：`docs\u002Fui\u002Ftask-grouped-view.md`、`docs\u002Fui\u002Fsidebar-task-view-switcher.md`。\n- 已废弃（保留仅供降级理解）：`docs\u002Fgrouped-task-workspace-bootstrap.md`、`apps\u002Fzcode-cli\u002Fdocs\u002Fdesign\u002Fv2\u002Fmulti-workspace.md`。\n",{"name":5,"description":7},"main","cf24e347c4aaf1182ef9fa1f9743a80ab14ff638",".agents\u002Fskills\u002Fsession-management",20,"https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium","https:\u002F\u002Fzcodium-project.github.io\u002F","https:\u002F\u002Fgithub.com\u002FZCodium-project","zcodium-project.github.io\u002F","Zcode Open Audit Version.","2026-11-13 18:44:38",{"source":8,"skillName":5,"commands":35,"prompt":45,"zipAvailable":46},[36,39,42],{"tool":37,"command":38},"npx","npx skills add ZCodium-project\u002FZCodium --skill session-management",{"tool":40,"command":41},"bunx","bunx skills add ZCodium-project\u002FZCodium --skill session-management",{"tool":43,"command":44},"pnpm","pnpm dlx skills add ZCodium-project\u002FZCodium --skill session-management","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002F.agents\u002Fskills\u002Fsession-management\u002FSKILL.md",true,[],[49,56,63,70,77,84],{"skillNo":50,"name":51,"nameZh":6,"description":52,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":53,"categories":54,"keywords":55,"publishedAt":19},"01M7DBYM2HAMB3K65Q3XET0XWW","plugin-mcp-ping","E2E workspace Plugin skill marker","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002Fpackages\u002Fdesktop\u002Ftest\u002Fe2e\u002Ffixtures\u002Fplugin-mcp-skill\u002Fe2e-plugin-mcp-ping\u002Fskills\u002Fplugin-mcp-ping\u002FSKILL.md",[],[],{"skillNo":57,"name":58,"nameZh":6,"description":59,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":60,"categories":61,"keywords":62,"publishedAt":19},"01M7DBYCTV753XKE9TRBT8CRSX","zcode-configuration-guide","Use when configuring ZCode's extension resources (MCP servers, slash commands, skills, hooks, and plugins) or instruction files such as AGENTS.md in the ZCode client. Explains where each resource is configured at the user and workspace scope, the discovery order, precedence, and merge rules, plus guidance on which location to choose. Use when someone asks how to add an MCP server, command, skill, hook, plugin, or AGENTS.md instructions, where a configuration file lives, why a configuration is not taking effect, or needs routing to a specific diagnostic skill.","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002Fapps\u002Fzcode-cli\u002Fpackages\u002Fzcode-guide-plugin\u002Fskills\u002Fzcode-configuration-guide\u002FSKILL.md",[],[],{"skillNo":64,"name":65,"nameZh":6,"description":66,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":67,"categories":68,"keywords":69,"publishedAt":19},"01M7DBY4P7GEEPQZ5VSWCF0YS1","diagnosing-skills","Use to diagnose and fix ZCode skill configuration problems in the ZCode client. Applies when a skill is not discovered, is installed but does not trigger automatically, is shadowed by a higher-precedence skill of the same name, is disabled by configuration, has a SKILL.md frontmatter error, fails to load because its description is too long, or disappears because the plugin providing it is disabled. Provides the discovery order, how to inspect skills in the client, common pitfalls, and a step-by-step localization and repair workflow.","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002Fapps\u002Fzcode-cli\u002Fpackages\u002Fzcode-guide-plugin\u002Fskills\u002Fdiagnosing-skills\u002FSKILL.md",[],[],{"skillNo":71,"name":72,"nameZh":6,"description":73,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":74,"categories":75,"keywords":76,"publishedAt":19},"01M7DBXS9PAV8Z09309HMYMNPC","diagnosing-plugins","Use to diagnose and fix ZCode plugin and marketplace problems in the ZCode client. Applies when a plugin is not listed, adding a marketplace or installing a plugin fails, a plugin is enabled but its skills or commands are missing, a built-in plugin still appears after being disabled, a plugin is not enabled as expected, a plugin.json manifest has a parse error, a plugin name is invalid, a dependency is unresolved or blocked across marketplaces, or a sensitive configuration value cannot be entered in the interface. Provides the plugin lifecycle, manifest schema, how to manage plugins in the client, and a step-by-step localization and repair workflow.","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002Fapps\u002Fzcode-cli\u002Fpackages\u002Fzcode-guide-plugin\u002Fskills\u002Fdiagnosing-plugins\u002FSKILL.md",[],[],{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":19},"01M7DBXHJ0G1KZDC405HYQBHB6","diagnosing-mcp","Use to diagnose and fix ZCode MCP (Model Context Protocol) server configuration problems in the ZCode client. Applies when an MCP server will not connect, its tools (mcp__server__tool) do not appear, it shows as disabled or failed, connections time out, a command cannot be found, template variables are not expanded, or a server defined in a configuration file has no effect. Provides configuration locations, how to inspect status in Settings, common pitfalls, and a step-by-step localization and repair workflow.","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002Fapps\u002Fzcode-cli\u002Fpackages\u002Fzcode-guide-plugin\u002Fskills\u002Fdiagnosing-mcp\u002FSKILL.md",[],[],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":19},"01M7DBXABP8ZRNM6TFWDJXJH9Z","diagnosing-hooks","Use to diagnose and fix ZCode hook configuration problems in the ZCode client. Applies when a hook does not trigger, an event name is wrong, a matcher does not match a tool name, a script is not executable, template variables are not expanded, a timeout unit is mistaken (seconds versus milliseconds), the command and process field styles are mixed, a hook's JSON output fails validation, a hook blocks the session unexpectedly, or configuration-file hooks are not enabled. Provides configuration sources, the hooks.json schema, how to inspect hooks in the client, and a step-by-step localization and repair workflow.","https:\u002F\u002Fgithub.com\u002FZCodium-project\u002FZCodium\u002Fblob\u002Fmain\u002Fapps\u002Fzcode-cli\u002Fpackages\u002Fzcode-guide-plugin\u002Fskills\u002Fdiagnosing-hooks\u002FSKILL.md",[],[]]