# ccgui-index 代码索引优化方案

> 本文档供本项目负责 agent 执行。每项任务均已标注涉及文件、现状、改动点与验收标准，可逐项落地。
> 执行时请遵循本项目既有代码风格与规范（中文注释、不使用 emoji、保持简洁专业）。

## 一、当前实现概览（先读这些文件建立上下文）

代码索引子系统位于 `src-tauri/src/`：

| 文件 | 职责 |
| --- | --- |
| `index/mod.rs` | 索引管理器、后台单线程任务（Scan/Update/Drop）、全量扫描与增量、MCP 注册 |
| `index/parse.rs` | tree-sitter-tags 抽取符号 + 导入；`lang_for_ext` 语言映射 |
| `index/db.rs` | SQLite schema 与读写（`files`/`symbols`/`imports` 三表） |
| `index/query.rs` | 五个查询实现 |
| `index/server.rs` | MCP stdio 服务器（`--mcp-index` 模式），工具定义与分发 |
| `watch.rs` | notify 递归文件监听 + 500ms 去抖 → 增量更新 |

技术栈：Rust + tree-sitter-tags + SQLite(WAL, rusqlite)，后台单线程顺序索引。

数据模型：
- `files(id, rel_path, mtime_ms, lang)`
- `symbols(id, file_id, name, kind, is_def, start_line, end_line, signature)`
- `imports(id, file_id, module)` —— `module` 为**原始导入字符串**，未解析为实际文件

当前支持语言：rust、js/mjs/cjs/jsx、ts/mts/cts、tsx、py/pyi、go。

MCP 暴露的五个工具：`search_symbols`、`goto_definition`、`file_outline`、`find_references`、`module_graph`。

## 二、执行约定（务必先读）

1. **改 schema 无需写迁移**：`db.rs` 中 `SCHEMA_VERSION` 递增后，`init_schema` 会自动 DROP 旧表重建（索引是可再生数据）。任何表结构变动只需 `SCHEMA_VERSION += 1`。
2. **改完跑测试**：`parse.rs`、`db.rs` 已有单元测试，`cargo test` 应全绿；新增能力请补测试。
3. **MCP 端是独立只读子进程**：`server.rs::run_stdio` 以只读连接打开索引库，循环复用同一连接（WAL 下可见主进程后续提交，无需重开）。新增工具在 `tool_defs()` 注册、在 `handle_call` 分发。
4. **索引库是单项目独立文件**：`%APPDATA%\ccgui\index\<hash>.db`，按项目根路径 FNV-1a 命名。

## 三、关于「新鲜度」的结论（先对齐认知，避免做错方向）

本系统**已是实时增量**：`watch.rs` 用 notify 递归监听 + 500ms 去抖，去抖后将变更路径集合交给 `index::on_files_changed` → 增量 `update_files`。正常编辑流程下，保存文件约 1 秒内索引即跟上。**因此不存在「索引整体陈旧」问题，不要去做定时全量重建。**

仅存在以下**边界窗口**，作为局部补丁处理（见任务 P0-2）：
- git 批量操作（checkout/pull/rebase）改动大量工作区文件时，Windows `ReadDirectoryChangesW` 缓冲区可能溢出而**静默丢事件**，导致索引与磁盘不一致且不自愈。
- 保存后约 1 秒的去抖 + 排队窗口。
- CCGUI 未运行 / 未打开该项目 / 首次全量扫描未完成 / `index_enabled` 关闭期间发生的变更。

## 四、优化任务清单（按落地顺序）

### P0-1　新增 `get_symbol_source` 工具：直接返回符号源码

**现状**：`symbols` 表已存 `start_line`/`end_line`，但 Agent 拿到行号后仍需再 `Read` 文件一次才能看到实现，多一次往返。

**改动**：
- `server.rs`：`run_stdio` 已持有 `project_root`，但 `handle`/`handle_call` 当前只接收 `conn`。将 `project_root`（或拼好的根路径）透传进 `handle_call`。
- 新增工具 `get_symbol_source`，入参 `name`（必填）、可选 `kind`、可选 `path`（限定文件）。逻辑：先按 `goto_definition` 定位，再用 `project_root + rel_path` 读磁盘文件，截取 `start_line..=end_line` 返回源码片段（带文件名与行号）。
- 在 `tool_defs()` 注册该工具。
- 读文件需做大小与存在性保护，失败返回友好提示而非 panic。

**验收**：对任一已索引函数调用 `get_symbol_source`，返回完整函数体源码，无需再单独 Read。

### P0-2　监听丢事件的兜底对账 scan

**现状**：notify 在 git 批量操作下可能丢事件，且无自愈。

**改动**：
- 利用现有 `IndexState::scan`（普通扫描即 mtime 对账：遍历全项目，仅重解析 mtime 变化的文件，开销小）。
- 在 **应用窗口重新获得焦点（focus）时**触发一次 `scan`（需定位 Tauri 窗口事件注册处，通常在 `lib.rs`/`main.rs` 的 setup 或窗口事件回调中）。可加节流（如距上次对账 > 30s 才执行），避免频繁触发。
- 仅在 `index_enabled` 为真时执行。

**验收**：在外部对工作区做 git 切分支后切回 CCGUI 窗口，索引能在一次对账后与磁盘一致。

### P1-1　导入路径解析：`imports.module` → 实际文件（后续准确性的地基）

**现状**：`imports.module` 存的是 `@/stores/cloud-auth`、`./a`、`pinia` 等原始 specifier，从未 resolve 到项目内真实文件，导致无法做反向依赖与引用消歧。

**改动**：
- `db.rs`：`imports` 表新增 `resolved_file_id INTEGER NULL`（外键引用 `files(id)`），`SCHEMA_VERSION += 1`。
- 解析策略（在入库阶段或一遍扫描后处理）：
  - 相对路径 `./` `../` 按当前文件目录拼接并规范化；
  - TS/JS 读取项目 `tsconfig.json`/`jsconfig.json` 的 `compilerOptions.paths`（如 `@/*`）做别名映射；
  - 补全后缀与 index 文件（`.ts/.tsx/.js/.jsx`、`/index.*`）；
  - 解析不到（如第三方包 `pinia`）则 `resolved_file_id` 留空。
- 注意增量更新时新增文件可能让既有未解析导入变为可解析，可在对账 scan 时重算或接受最终一致。

**验收**：`module_graph` 返回的本地导入能对应到具体文件；第三方包仍以裸名保留。

### P1-2　反向依赖查询 `who_imports`（图谱核心能力）

**现状**：`module_graph` 只能正向列「我导入了什么」，无法回答「谁导入了我 / 改这个文件波及谁」。

**改动**：依赖 P1-1。`query.rs` 新增 `who_imports(conn, rel)`：按 `resolved_file_id` 反查所有导入该文件的文件。`server.rs` 注册同名工具。

**验收**：对某 store/util 文件查询，返回所有 import 它的文件列表。

### P1-3　引用消歧：为 `find_references` 增加置信度

**现状**：`find_references` 纯按 `name` 字符串匹配 `is_def=0`，跨文件同名引用全部混在一起，无归属。

**改动**：依赖 P1-1。在返回的每条引用上附置信度：当引用所在文件确实 import 了该符号定义所在文件时标为高置信，否则为低置信；高置信优先排序。保留「基于语法标记、非完整语义解析」的说明，但让调用方可据置信度取舍。

**验收**：对一个存在多处同名定义的符号查引用，能区分出真正指向目标定义的高置信引用。

### P2-1　全文检索（FTS5）

**现状**：仅索引符号，搜字符串字面量、报错文案、TODO、配置 key 必须回退 grep；且 `search_symbols` 用 `LIKE '%q%'` 前导通配符无法命中 `idx_symbols_name`，大项目下退化为全表扫描。

**改动**：`db.rs` 增加 SQLite FTS5 表（按文件或按行存内容），`SCHEMA_VERSION += 1`；`query.rs` 新增 `search_text`；`server.rs` 注册工具。可一并用 FTS/trigram 加速符号模糊搜索。注意 FTS 会增大库体积，评估是否仅对源码行建索引。

**验收**：能检索到注释、字符串字面量中的关键词；符号模糊搜索在大项目下响应稳定。

### P2-2　扩充语言覆盖

**现状**：仅 6 类语言。`lang_for_ext` 增分支即可扩展，tree-sitter-tags 成本低。

**改动**：在 `parse.rs::lang_for_ext` 增加分支并在 `Cargo.toml` 引入对应 tree-sitter crate，建议优先 PHP（对应云控端 Laravel）、Java、C#、C/C++、Ruby。各语言补 `*_IMPORTS` 查询与必要的 tags 拼接（参考 TS 的处理）。

**验收**：新增语言文件能被 `search_symbols`/`file_outline` 检索到。

### P2-3　解析可观测性

**现状**：tags 配置构建失败时整语言静默降级（`parse.rs` 已注释说明），单文件解析失败无记录，难以发现索引盲区。

**改动**：记录解析失败的文件与原因（新增轻量表或状态计数），并可经 MCP `index_status` 暴露。

**验收**：能查询到「哪些文件未成功解析」。

### P3（按需，成本较高）

- **多行签名**：`parse.rs` 的 `signature` 取定义首行并截断 200 字符，多行参数列表/装饰器会丢信息。可改存完整签名节点范围或附 doc comment 首行。
- **索引状态可观测性**：将 `ProjectStatus`（现仅在主进程内存）落库（meta 表存 `last_scan_ms` 等），经 MCP 暴露 `index_status`，让 Agent 能判断结果可信度。注意：因增量已足够可靠，本项价值有限，列为可选。
- **调用/继承层级**：call hierarchy、类继承关系，在 P1-1 基础上扩展，成本高，按需求排期。

## 五、落地顺序与依赖

```
P0-1  get_symbol_source        （独立，最先做，改动最小）
P0-2  兜底对账 scan            （独立）
P1-1  导入路径解析            （P1-2 / P1-3 的前置）
 ├─ P1-2  who_imports
 └─ P1-3  引用消歧
P2-1  FTS5 全文检索            （独立）
P2-2  扩语言                  （独立）
P2-3  解析可观测性            （独立）
P3    多行签名 / 索引状态 / 层级（按需）
```

价值排序：P1 系列（准确性，图谱独有价值）> P0（即时体验与监听补丁）> P2（覆盖更多检索场景）> P3。
