DeepSeek-Reasonix 会话索引(Session Catalog):SQLite 查询投影架构与桌面启动实践指南
【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix
本文以仓库文档 docs/SESSION_CATALOG.zh-CN.md 为核心骨架,结合
internal/sessioncatalog包源码与桌面端实现,系统讲解 Reasonix 的会话索引机制:它以 transcript/event log/metadata sidecar 为唯一权威数据,将桌面项目树读取收敛为对<缓存根目录>/session-catalog/v8.sqlite的一次性 SQLite 查询投影。读完本文,你将掌握该投影的设计动机、不变量、存储与迁移细节、桌面 API、运维命令以及发布门禁要求,能够在实际排查与调优中直接落地。
为什么需要一个"可丢弃"的会话索引
Reasonix 是面向终端、围绕 prefix-cache 稳定性设计的 AI coding agent。一个长期运行的会话会不断追加 transcript JSONL、event log 与 metadata sidecar,这些文件本身就是唯一权威数据(authoritative data)。如果桌面侧栏每刷新一次就扫描整个磁盘目录、解码全部 JSONL,不仅启动变慢,还会在 agent 忙于推理时与核心 IO 争抢资源,破坏 prefix-cache 的稳定性。
解决方案是把"树形展示需要的一切"沉淀为一次性 SQLite 查询投影:位于<缓存根目录>/session-catalog/v8.sqlite。它的核心特征在 internal/sessioncatalog/types.go 的包注释中写得很清楚:
Package sessioncatalog maintains a disposable SQLite projection of Reasonix session sidecars. Session JSONL/event/meta files remain authoritative; every row in this package may be discarded and rebuilt.
即:索引里的每一行都可以被删除并重建,删除该数据库不会删除或修改任何会话。这是理解整个模块的一把钥匙——投影是可推导的,权威数据在文件系统上。
目录中的早期v1.sqlite至v5.sqlite缓存会被保留。原因是防止仍在运行的旧版本进程(或回滚降级后的版本)与新版交叉写同一个投影文件;v6 引入文件系统感知的路径身份后,首次启动会从权威文件重新建立索引,旧 v5 文件仅用于回滚且不会被新版本写入。同一 v6 索引的手动重建也会留下带时间戳的.replaced-*旧文件,便于随时回退。当前实现中生产默认路径已演进到 DefaultPath() 返回的v8.sqlite,注释明确说明 v8 是为了把 v12 的 head 投影与 v11 的写入者隔离。
不变量:保证索引永远可被丢弃、可重建
原文档列出了九条不变量,它们是整个模块的正确性契约,逐条对应源码实现:
- 启动与项目树请求零负担:启动和项目树请求不会解码 transcript JSONL、执行旧版迁移或等待目录扫描。桌面 API 全部走 catalog 快照(见"桌面 API"一节),
ListProjectTree也声明"不再回退到同步文件系统扫描"。 - 落盘后再更新:只有 transcript 成功落盘后 catalog 才会更新。保存观察器只做词法队列入队,不做文件系统探测;后台 worker 解析文件系统身份,SQLite 唯一约束作为最终去重边界;目录对账(reconcile)会修复队列拥塞时丢弃的更新。对应实现见 index_queue.go 与 reconcile.go。
- 路径拼写 vs 身份 key:session 和 workspace root 的原始路径拼写继续用于文件访问和展示;独立的 identity key 会解析别名(如符号链接),并且只在所属文件系统目录不区分大小写时折叠大小写——大小写敏感卷上的不同文件和项目不会被错误合并。跨平台的路径身份实现见 path_identity.go 及 darwin/windows 平台变体。
unknown状态立即可见:缺少旧版计数时使用unknown状态,会话立即在侧栏可见,随后由单个 repair worker 在后台解码修复。TurnsState的三种取值unknown/valid/corrupt定义在 types.go。- 过期投影不消失:保存在写入列表戳记前被中断产生的过期投影同样是
unknown,但保留最近一次已知的 preview 和回合数作为"未认证的提示",修复期间该行不会从侧栏消失。 - 两级缺失判定:文件首次缺失只标记为
degraded;只有连续第二次扫描仍缺失且超过宽限期后,才会从查询投影移除。健康状态ok/missing/corrupt/degraded定义在 types.go,宽限期可通过Options.MissingGrace配置。 - 运行时状态不入库:
open、running等实时状态只来自内存 controller 并覆盖 catalog 结果,永远不持久化到 SQLite。 - 可取消、不阻塞退出:catalog、迁移、插件和 MCP 工作都可取消,不参与桌面退出锁;退出最多等待 catalog 待写入数据 250 ms。桌面端退出路径见 shutdown.go 与 session_catalog_runtime.go。
- ready 状态必须一致:只有磁盘会话路径、scope/workspace、topic 投影和恢复派生字段均与当前权威文件一致时 ready 状态才可复用;数量相等但路径错位也会触发重建。状态机
opening/ready/degraded/rebuilding/closed定义在 types.go。
存储与迁移:从 v1 到 v12 的演进
迁移台账与打开语义
internal/sessioncatalog使用schema_migrations版本台账(来自internal/projectiondb的Migration结构):数据库文件存在不代表迁移完成。打开时逐版本执行 sessionMigrations() 中注册的 12 个迁移。
WAL 与降级策略
本地缓存使用 WAL、synchronous=NORMAL和 150ms 的较短 busy timeout。这些 pragma 在 internal/projectiondb/projectiondb.go 中统一设置:
PRAGMA journal_mode=WAL PRAGMA synchronous=NORMAL PRAGMA foreign_keys=ON PRAGMA busy_timeout=150Windows 上还做了 DSN 规范化(C:/Users/...→file:///C:/Users/...),避免裸file:C:\...URI 打开失败导致静默降级到内存(projectiondb.go)。当缓存目录不可用或明确位于远程文件系统时,会降级为内存 catalog(ModeMemory,连接池限制为 1 以规避 shared-cache 并发写问题),避免存储故障阻塞应用。磁盘模式默认连接池上限为 4。
损坏恢复
打开数据库时 Reasonix 会执行完整性检查。损坏或无法迁移的数据库会被重命名,附加.corrupt-<时间戳>后缀并由新数据库替代;随后在后台根据 sidecar 和 transcript 重建。隔离和重建都不会删除权威文件。
投影中存什么
catalog 只保存查询投影(schema.go 的 v1 基表定义):
catalog_directories:目录签名(signature)、扫描代次(scan_generation)、检查点(scan_cursor)与错误;catalog_projects:项目排序、标题、颜色、置顶状态及 workspace root identity key;catalog_topics:topic 排序、聚合计数(turns)、活动时间、恢复、健康状态及 workspace root identity key;catalog_sessions:session 访问路径及 path/directory/workspace root identity key、preview、计数、内容与元数据指纹(content_fingerprint/meta_fingerprint)、恢复与健康状态;catalog_heads:对 schema 2 事件日志,记录日志格式(log_format)、选中 head(selected_head_id),以及每个 head 一行的 head 投影,来源是内核写出的 head 索引侧车与BranchMeta镜像,而不是重放日志(v12 迁移,schema.go)。
关键索引(schema.go)保证了分页与过滤的查询路径:idx_catalog_topics_page直接支撑(pinned, last_activity_at, topic_id)的 keyset 分页;idx_catalog_sessions_directory支撑按目录的(directory, seen_generation, missing_since)扫描。
版本演进路线
迁移历史本身就是索引设计的演进史(schema.go):
| 版本 | 内容 | 意义 |
|---|---|---|
| v1 | 基表与索引 | 目录/项目/topic/session 四类投影 |
| v2 | topics 增加metadata_present | 区分 topic 标题来源 |
| v3 | sessions 增加历史查询索引 | 按 workspace 的活动时间分页 |
| v4 | sessions 增加recovery_copy | 恢复副本标记 |
| v5 | sessions 增加recovery_group_id/role/canonical | 恢复血缘分组(v6/v7 继续扩展 branch 计数与逻辑 topic) |
| v7 | sessions 增加logical_topic_id、ordinary_visible | 恢复副本重新锚定到逻辑 topic |
| v8 | 新增catalog_folded_topicstombstone | 防止恢复副本的旧 topic 在行移走后复活为侧栏行 |
| v9 | 引入path_key/directory_key并清空重建 | 文件系统感知的身份与访问拼写分离;SQL 无法安全回填,故删除全部投影等待对账重建 |
| v10 | 引入workspace_root_key并清空重建 | 身份扩展至 workspace root,唯一性全部基于文件系统 key |
| v11 | sessions 增加 repair 调度字段 | 持久化修复重试预算(repair_state/attempts/retry_at/error_kind) |
| v12 | heads 投影 + 生成文件迁到 v8.sqlite | schema 2 事件日志的多 head 展示支持 |
其中 v9/v10 是破坏性迁移(DELETE FROM全表),注释明确说明"现有投影是一次性的,必须重建,因为 SQL 无法推断卷级的大小写语义"——这正是"身份 key 与展示拼写分离"设计的具体落地。
对账与分页参数
- topic 分页使用
(pinned, last_activity_at, topic_id)keyset cursor(topic_cursor.go),默认每页 50 条、最多 200 条(DefaultLimit/MaxLimit,types.go); - 目录对账每批最多提交 64 个 sidecar,并在让出调度前持久化检查点(reconcile.go 与
commitDirectoryProjection中的同批 64 上限)。手动排序(ManualOrder)是请求级作用域,从未手动排序的用户保持活动时间排序,即使 metadata 行已有 sort 值。
桌面 API:树、分页、状态与重建
桌面端通过 Wails App 方法暴露 catalog 能力,实现在 desktop/session_catalog.go 与 desktop/session_catalog_runtime.go:
GetProjectTreeSnapshot(session_catalog.go):返回项目壳、catalog 状态、进度和 revision,不打开 session 或 sidecar 文件;ListProjectTopics:基于 cursor 的分页搜索和时间过滤,参数见TopicPageRequest(scope、workspaceRoot、cursor、limit、query、timeFilter、sortMode、manualOrder);GetTopicSummary:为 active-turn UI 查询单个 topic,无需重建整棵树;GetSessionCatalogStatus(session_catalog_runtime.go)与RebuildSessionCatalog(session_catalog_rebuild.go):提供安全诊断与索引替换。状态同时报告最近修复原因(repairReason)、源文件数量(sourceCount)和未完成的目录目标,项目树提供手动重建入口。Status结构还包含repairPending/active/deferred/blocked队列计数、physicalSessions/logicalSessions、recoveryGroups/branches/diverged、cleanupEligible与quarantinedPath等诊断字段(types.go);project-tree:changed-v2:携带单调递增的 revision、受影响 workspace root 和原因。客户端忽略旧 revision,只刷新受影响且已展开的项目。重建过程会先发出catalog_rebuild_started再发catalog_rebuild_finished,并保证替换 watcher 是普通 watcher、永不拥有重建权(session_catalog_rebuild.go)。
重建的并发语义值得注意:RebuildSessionCatalog是 bounded、one-shot 的 single-flight 事务,带 5 秒停止超时;Windows 上为避免原子替换与旧 SQLite handle 的竞态,必须先停旧实例再重建(session_catalog_rebuild.go),对应测试见 session_catalog_rebuild_concurrency_test.go 与 session_catalog_rebuild_timeout_test.go。
ListProjectTree作为基于 catalog 的兼容包装继续保留,不再回退到同步文件系统扫描——这是老 API 与索引架构之间的关键契约。
运维:诊断与重建命令
只读检查 catalog,不创建或修改它:
reasonix sessions diagnose reasonix sessions diagnose --json只替换一次性查询投影,并索引所有已保存的桌面项目:
reasonix sessions reindex reasonix sessions reindex --json可重复传入--dir PATH从指定目录集合重建;显式目录按 global scope 处理。reindex不会编辑或删除transcript、event、metadata、recovery、archive 或项目文件;旧索引文件会保留(.replaced-*),便于回滚。底层对应RebuildWithRevisionFloor(internal/sessioncatalog/reconcile.go),它保证新索引的 revision 不低于当前 revision,避免重建期间丢失已经发布的事件。
recovery-only 会话在普通树中显示为一个"可恢复"逻辑行;被覆盖的物理副本仍只在恢复历史中展示(RecoveryCopy为 true 且OrdinaryVisible仅对唯一的逻辑代表为 true,见 types.go),避免用户把未显示的副本误认为内容丢失。恢复角色的五种取值normal/covered_copy/adopted/preferred/diverged定义了血缘分类。
插件隔离与发布门禁
manifest 校验和插件握手与 catalog、项目树互相独立:不兼容插件报告为disabled_incompatible,核心 controller 仍可使用。Reasonix 管理目录中的旧版 manifest 会在生成备份后原子升级;开发目录、外部绝对路径和软链接源码不会被自动改写,而是给出手动迁移提示。
作为可丢弃投影,catalog 的改动必须纳入发布门禁。Preview/canary 晋级应观测:
- catalog 修复积压(repair pending/deferred/blocked);
- 重建失败率与隔离路径(
.corrupt-<时间戳>、quarantinedPath); - 分页延迟(
idx_*_page索引命中情况); - 队列压力与退出耗时(250 ms 上限)。
必须覆盖的测试面:旧版与损坏 fixture、确定性的生命周期竞态、go test -race、React 契约测试,以及受支持 macOS、Windows 和 Linux 架构的CGO_ENABLED=0构建。仓库中对应的大量测试(catalog_test.go、reconcile_integrity_test.go、repair_fencing_test.go、path_identity_migration_test.go 等)正是这些门禁的实现证据。
小结
会话索引的本质是一句口号:权威数据在文件系统,投影随时可重建。从 v1 到 v12 的迁移史展示了身份与拼写分离、恢复血缘、多 head 投影的演进;九条不变量保证了索引永远不会反过来绑架权威数据;桌面 API 让项目树读取零负担;sessions diagnose/reindex让运维可以在不触碰任何会话文件的前提下完成诊断与重建。理解这套架构,是排查桌面侧栏异常、评估索引延迟与规划发布晋级的第一步。
延伸阅读
- 索引设计文档:docs/SESSION_CATALOG.zh-CN.md(本文骨架,另有英文版
SESSION_CATALOG.md) - 包实现入口:internal/sessioncatalog(schema/types/catalog/reconcile/repair/lineage/path_identity 等)
- 数据库基础设施:internal/projectiondb/projectiondb.go
- 桌面集成:desktop/session_catalog.go、desktop/session_catalog_runtime.go、desktop/session_catalog_rebuild.go
- 相关会话架构文档:docs/SESSION_RECOVERY_AND_PARALLELISM.zh-CN.md、docs/SESSION_OWNERSHIP.zh-CN.md
【免费下载链接】DeepSeek-ReasonixDeepSeek-native AI coding agent for your terminal. Engineered around prefix-cache stability — leave it running.项目地址: https://gitcode.com/GitHub_Trending/de/DeepSeek-Reasonix
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考