# 04 - 工作区文件索引（Workspace Index）

## 概述

Workspace Index 为天工提供项目文件结构感知，用于辅助 Planner 和 Recall 定位相关文件。

> **实现状态**：Workspace Index 将按 RFC 0012 在 `tiangong-core/src/index/` 中实现，使用 Tantivy 替代原 JSON 文件方案。不再放在 `tiangong-memory` crate。详见 `docs/rfc/0012-workspace-session-indexing.md`。

## 与现有工具能力的边界

天工已有以下文件相关的工具能力：

| 已有工具 | 能力 | Workspace Index 的区别 |
|---------|------|----------------------|
| `list_directory` | 列出目录内容 | 被动调用 vs 主动索引 |
| `read_file` | 读取文件内容 | 全文 vs 结构摘要 |
| `code_search` | 全文搜索 | 精确匹配 vs 语义关联 |
| `find_symbol` | 符号查找 | 单次查找 vs 持久索引 |

**Workspace Index 的独特价值**：

1. **提前加载**：在 turn 开始前就知道项目结构，不需要额外工具调用
2. **持久化**：索引结果缓存，避免重复扫描
3. **语义增强**：文件不只是路径，还有功能标注和关联关系
4. **轻量注入**：只注入文件树摘要，不是全部内容

---

## 两层索引

### Layer 1: 文件树索引

**目标**：快速获知项目有哪些文件和目录。

**存储路径**：`~/.tiangong/workspace-index/<workspace_id>/file-tree.json`

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileTreeIndex {
    pub workspace_id: String,
    pub root_path: String,
    pub updated_at: String,
    pub entries: Vec<FileEntry>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FileEntry {
    pub path: String,          // 相对于 workspace root
    pub entry_type: FileType,
    pub size_bytes: u64,
    pub modified_at: String,
    pub annotation: Option<String>,  // 功能标注（可选）
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FileType {
    File,
    Directory,
}
```

**构建策略**：

```rust
pub fn build_file_tree(
    root: &Path,
    ignore_patterns: &[String],
) -> FileTreeIndex {
    // 遵循 .gitignore + 自定义忽略规则
    // 默认忽略：target/, node_modules/, .git/, __pycache__/
    // 限制深度：最大 6 层
    // 限制数量：最多 2000 个条目
    todo!()
}
```

**更新触发**：
- 会话启动时，如果索引文件超过 30 分钟未更新
- 文件操作工具（write_file, create_file）执行后，增量更新受影响的条目
- 用户显式请求刷新

---

### Layer 2: 符号索引（Phase D）

**目标**：提供模块/函数/结构体级别的语义索引。

**存储路径**：`~/.tiangong/workspace-index/<workspace_id>/symbols.json`

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolIndex {
    pub workspace_id: String,
    pub updated_at: String,
    pub symbols: Vec<SymbolEntry>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SymbolEntry {
    pub name: String,
    pub kind: SymbolKind,
    pub file_path: String,
    pub line_range: (u32, u32),
    pub signature: Option<String>,  // 函数签名
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SymbolKind {
    Module,
    Struct,
    Enum,
    Function,
    Trait,
    Impl,
    Constant,
}
```

**构建策略**：
- 利用 `tree-sitter` 解析 Rust/TypeScript/Python 源码
- 仅提取顶层和一级嵌套符号，不做深度 AST 分析
- 当前阶段（Phase D）优先支持 Rust

---

## Prompt 注入方式

文件树摘要作为 SystemContext 的一部分注入：

```
[项目结构]
crates/
  tiangong-core/src/
    prompt/assembler.rs    - Prompt 装配
    prompt/sections.rs     - 各段构建
    context/memory.rs      - Memory 存储
    context/organizer.rs   - 上下文管理
  tiangong-types/src/      - 共享类型
  tiangong-llm/src/        - LLM 客户端抽象
frontend/src/
  components/              - UI 组件
  pages/                   - 页面
```

**注入预算**：文件树摘要限制在 300 tokens 以内。使用折叠策略：
- 只展开有标注的目录
- 叶子文件只显示关键文件
- 超过 5 个同类文件的目录折叠为 `... (N files)`

---

## 实现优先级

| 阶段 | 内容 | 依赖 |
|------|------|------|
| Phase A | 不实现 | - |
| Phase B | 不实现 | - |
| Phase C | Layer 1 文件树（可选） | file-tree 扫描 |
| Phase D | Layer 1 + Layer 2 首期 | Tantivy BM25 索引，轻量 Rust 行级符号扫描 |

Workspace Index 属于增强功能，Phase A/B 的核心价值不依赖它。按 RFC 0012 方案在 `tiangong-core/src/index/` 中使用 Tantivy 实现，存储在 `~/.tiangong/index/` 目录。
