feat(cli): 添加 --rule 选项支持模板自动发现

重构 ccw cli 模板系统:

- 新增 template-discovery.ts 模块,支持扁平化模板自动发现
- 添加 --rule <template> 选项,自动加载 protocol 和 template
- 模板目录从嵌套结构 (prompts/category/file.txt) 迁移到扁平结构 (prompts/category-function.txt)
- 更新所有 agent/command 文件,使用 $PROTO $TMPL 环境变量替代 $(cat ...) 模式
- 支持模糊匹配:--rule 02-review-architecture 可匹配 analysis-review-architecture.txt

其他更新:
- Dashboard: 添加 Claude Manager 和 Issue Manager 页面
- Codex-lens: 增强 chain_search 和 clustering 模块

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
catlog22
2026-01-17 19:20:24 +08:00
parent 1fae35c05d
commit f14418603a
137 changed files with 13125 additions and 301 deletions

View File

@@ -0,0 +1,676 @@
# Codexlens LSP API 规范
**版本**: 1.1
**状态**: ✅ APPROVED (Gemini Review)
**架构**: codexlens 提供 Python APICCW 实现 MCP 端点
**分析来源**: Gemini (架构评审) + Codex (实现评审)
**最后更新**: 2025-01-17
---
## 一、概述
### 1.1 背景
基于 cclsp MCP 服务器实现的分析,设计 codexlens 的 LSP 搜索方法接口,为 AI 提供代码智能能力。
### 1.2 架构决策
**MCP 端点由 CCW 实现codexlens 只提供 Python API**
```
┌─────────────────────────────────────────────────────────────┐
│ Claude Code │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ MCP Client │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ CCW MCP Server │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ MCP Tool Handlers │ │ │
│ │ │ • codexlens_file_context │ │ │
│ │ │ • codexlens_find_definition │ │ │
│ │ │ • codexlens_find_references │ │ │
│ │ │ • codexlens_semantic_search │ │ │
│ │ └──────────────────────┬──────────────────────────┘ │ │
│ └─────────────────────────┼─────────────────────────────┘ │
└────────────────────────────┼────────────────────────────────┘
│ Python API 调用
┌─────────────────────────────────────────────────────────────┐
│ codexlens │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ Public API Layer │ │
│ │ codexlens.api.file_context() │ │
│ │ codexlens.api.find_definition() │ │
│ │ codexlens.api.find_references() │ │
│ │ codexlens.api.semantic_search() │ │
│ └──────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────────┐ │
│ │ Core Components │ │
│ │ GlobalSymbolIndex | ChainSearchEngine | HoverProvider │ │
│ └───────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────────▼────────────────────────────────┐ │
│ │ SQLite Index Databases │ │
│ │ global_symbols.db | *.index.db (per-directory) │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
### 1.3 职责分离
| 组件 | 职责 |
|------|------|
| **codexlens** | Python API、索引查询、搜索算法、结果聚合、降级处理 |
| **CCW** | MCP 协议、参数校验、结果序列化、错误处理、project_root 推断 |
### 1.4 codexlens vs cclsp 对比
| 特性 | cclsp | codexlens |
|------|-------|-----------|
| 数据源 | 实时 LSP 服务器 | 预建 SQLite 索引 |
| 启动时间 | 200-3000ms | <50ms |
| 响应时间 | 50-500ms | <5ms |
| 跨语言 | 每语言需要 LSP 服务器 | 统一 Python/TS/JS/Go 索引 |
| 依赖 | 需要语言服务器 | 无外部依赖 |
| 准确度 | 100% (编译器级) | 95%+ (tree-sitter) |
| 重命名支持 | 是 | 否 (只读索引) |
| 实时诊断 | 是 | 通过 IDE MCP |
**推荐**: codexlens 用于快速搜索cclsp 用于精确重构
---
## 二、cclsp 设计模式 (参考)
### 2.1 MCP 工具接口设计
| 模式 | 说明 | 代码位置 |
|------|------|----------|
| **基于名称** | 接受 `symbol_name` 而非文件坐标 | `index.ts:70` |
| **安全消歧义** | `rename_symbol``rename_symbol_strict` 两步 | `index.ts:133, 172` |
| **复杂性抽象** | 隐藏 LSP 协议细节 | `index.ts:211` |
| **优雅失败** | 返回有用的文本响应 | 全局 |
### 2.2 符号解析算法
```
1. getDocumentSymbols (lsp-client.ts:1406)
└─ 获取文件所有符号
2. 处理两种格式:
├─ DocumentSymbol[] → 扁平化
└─ SymbolInformation[] → 二次定位
3. 过滤: symbol.name === symbolName && symbol.kind
4. 回退: 无结果时移除 kind 约束重试
5. 聚合: 遍历所有匹配,聚合定义位置
```
---
## 三、需求规格
### 需求 1: 文件上下文查询 (`file_context`)
**用途**: 读取代码文件,返回文件中所有方法的调用关系摘要
**输出示例**:
```markdown
## src/auth/login.py (3 methods)
### login_user (line 15-45)
- Calls: validate_password (auth/utils.py:23), create_session (session/manager.py:89)
- Called by: handle_login_request (api/routes.py:156), test_login (tests/test_auth.py:34)
### validate_token (line 47-62)
- Calls: decode_jwt (auth/jwt.py:12)
- Called by: auth_middleware (middleware/auth.py:28)
```
### 需求 2: 通用 LSP 搜索 (cclsp 兼容)
| 端点 | 用途 |
|------|------|
| `find_definition` | 根据符号名查找定义位置 |
| `find_references` | 查找符号的所有引用 |
| `workspace_symbols` | 工作区符号搜索 |
| `get_hover` | 获取符号悬停信息 |
### 需求 3: 向量 + LSP 融合搜索
**用途**: 结合向量语义搜索和结构化 LSP 搜索
**融合策略**:
- **RRF** (首选): 简单、不需要分数归一化、鲁棒
- **Cascade**: 特定场景,先向量后 LSP
- **Adaptive**: 长期目标,按查询类型自动选择
---
## 四、API 规范
### 4.1 模块结构
```
src/codexlens/
├─ api/ [新增] 公开 API 层
│ ├─ __init__.py 导出所有 API
│ ├─ file_context.py 文件上下文
│ ├─ definition.py 定义查找
│ ├─ references.py 引用查找
│ ├─ symbols.py 符号搜索
│ ├─ hover.py 悬停信息
│ └─ semantic.py 语义搜索
├─ storage/
│ ├─ global_index.py [扩展] get_file_symbols()
│ └─ relationship_query.py [新增] 有向调用查询
└─ search/
└─ chain_search.py [修复] schema 兼容
```
### 4.2 `codexlens.api.file_context()`
```python
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Tuple
@dataclass
class CallInfo:
"""调用关系信息"""
symbol_name: str
file_path: Optional[str] # 目标文件 (可能为 None)
line: int
relationship: str # call | import | inheritance
@dataclass
class MethodContext:
"""方法上下文"""
name: str
kind: str # function | method | class
line_range: Tuple[int, int]
signature: Optional[str]
calls: List[CallInfo] # 出向调用
callers: List[CallInfo] # 入向调用
@dataclass
class FileContextResult:
"""文件上下文结果"""
file_path: str
language: str
methods: List[MethodContext]
summary: str # 人类可读摘要
discovery_status: Dict[str, bool] = field(default_factory=lambda: {
"outgoing_resolved": False,
"incoming_resolved": True,
"targets_resolved": False
})
def file_context(
project_root: str,
file_path: str,
include_calls: bool = True,
include_callers: bool = True,
max_depth: int = 1,
format: str = "brief" # brief | detailed | tree
) -> FileContextResult:
"""
获取代码文件的方法调用上下文。
Args:
project_root: 项目根目录 (用于定位索引)
file_path: 代码文件路径
include_calls: 是否包含出向调用
include_callers: 是否包含入向调用
max_depth: 调用链深度 (1=直接调用)
⚠️ V1 限制: 当前版本仅支持 max_depth=1
深度调用链分析将在 V2 实现
format: 输出格式
Returns:
FileContextResult
Raises:
IndexNotFoundError: 项目未索引
FileNotFoundError: 文件不存在
Note:
V1 实现限制:
- max_depth 仅支持 1 (直接调用)
- 出向调用目标文件可能为 None (未解析)
- 深度调用链分析作为 V2 特性规划
"""
```
### 4.3 `codexlens.api.find_definition()`
```python
@dataclass
class DefinitionResult:
"""定义查找结果"""
name: str
kind: str
file_path: str
line: int
end_line: int
signature: Optional[str]
container: Optional[str] # 所属类/模块
score: float
def find_definition(
project_root: str,
symbol_name: str,
symbol_kind: Optional[str] = None,
file_context: Optional[str] = None,
limit: int = 10
) -> List[DefinitionResult]:
"""
根据符号名称查找定义位置。
Fallback 策略:
1. 精确匹配 + kind 过滤
2. 精确匹配 (移除 kind)
3. 前缀匹配
"""
```
### 4.4 `codexlens.api.find_references()`
```python
@dataclass
class ReferenceResult:
"""引用结果"""
file_path: str
line: int
column: int
context_line: str
relationship: str # call | import | type_annotation | inheritance
@dataclass
class GroupedReferences:
"""按定义分组的引用"""
definition: DefinitionResult
references: List[ReferenceResult]
def find_references(
project_root: str,
symbol_name: str,
symbol_kind: Optional[str] = None,
include_definition: bool = True,
group_by_definition: bool = True,
limit: int = 100
) -> List[GroupedReferences]:
"""
查找符号的所有引用位置。
多定义时分组返回,解决引用混淆问题。
"""
```
### 4.5 `codexlens.api.workspace_symbols()`
```python
@dataclass
class SymbolInfo:
"""符号信息"""
name: str
kind: str
file_path: str
line: int
container: Optional[str]
score: float
def workspace_symbols(
project_root: str,
query: str,
kind_filter: Optional[List[str]] = None,
file_pattern: Optional[str] = None,
limit: int = 50
) -> List[SymbolInfo]:
"""在整个工作区搜索符号 (前缀匹配)。"""
```
### 4.6 `codexlens.api.get_hover()`
```python
@dataclass
class HoverInfo:
"""悬停信息"""
name: str
kind: str
signature: str
documentation: Optional[str]
file_path: str
line_range: Tuple[int, int]
type_info: Optional[str]
def get_hover(
project_root: str,
symbol_name: str,
file_path: Optional[str] = None
) -> Optional[HoverInfo]:
"""获取符号的详细悬停信息。"""
```
### 4.7 `codexlens.api.semantic_search()`
```python
@dataclass
class SemanticResult:
"""语义搜索结果"""
symbol_name: str
kind: str
file_path: str
line: int
vector_score: Optional[float]
structural_score: Optional[float]
fusion_score: float
snippet: str
match_reason: Optional[str]
def semantic_search(
project_root: str,
query: str,
mode: str = "fusion", # vector | structural | fusion
vector_weight: float = 0.5,
structural_weight: float = 0.3,
keyword_weight: float = 0.2,
fusion_strategy: str = "rrf", # rrf | staged | binary | hybrid
kind_filter: Optional[List[str]] = None,
limit: int = 20,
include_match_reason: bool = False
) -> List[SemanticResult]:
"""
语义搜索 - 结合向量和结构化搜索。
Args:
project_root: 项目根目录
query: 自然语言查询
mode: 搜索模式
- vector: 仅向量搜索
- structural: 仅结构搜索 (符号 + 关系)
- fusion: 融合搜索 (默认)
vector_weight: 向量搜索权重 [0, 1]
structural_weight: 结构搜索权重 [0, 1]
keyword_weight: 关键词搜索权重 [0, 1]
fusion_strategy: 融合策略 (映射到 chain_search.py)
- rrf: Reciprocal Rank Fusion (推荐,默认)
- staged: 分阶段级联 → staged_cascade_search
- binary: 二分重排级联 → binary_rerank_cascade_search
- hybrid: 混合级联 → hybrid_cascade_search
kind_filter: 符号类型过滤
limit: 最大返回数量
include_match_reason: 是否生成匹配原因 (启发式,非 LLM)
Returns:
按 fusion_score 排序的结果列表
降级行为:
- 无向量索引: vector_score=None, 使用 FTS + 结构搜索
- 无关系数据: structural_score=None, 仅向量搜索
"""
```
---
## 五、已知问题与解决方案
### 5.1 P0 阻塞项
| 问题 | 位置 | 解决方案 |
|------|------|----------|
| **索引 Schema 不匹配** | `chain_search.py:313-324` vs `dir_index.py:304-312` | 兼容 `full_path``path` |
| **文件符号查询缺失** | `global_index.py:214-260` | 新增 `get_file_symbols()` |
| **出向调用查询缺失** | `dir_index.py:333-342` | 新增 `RelationshipQuery` |
| **关系类型不一致** | `entities.py:74-79` | 规范化 `calls``call` |
### 5.2 设计缺陷 (Gemini 发现)
| 缺陷 | 影响 | 解决方案 |
|------|------|----------|
| **调用图不完整** | `file_context` 缺少出向调用 | 新增有向调用 API |
| **消歧义未定义** | 多定义时无法区分 | 实现 `rank_by_proximity()` |
| **AI 特性成本过高** | `explanation` 需要 LLM | 设为可选,默认关闭 |
| **融合参数不一致** | 3 分支但只有 2 权重 | 补充 `keyword_weight` |
### 5.3 消歧义算法
**V1 实现** (基于文件路径接近度):
```python
def rank_by_proximity(
results: List[DefinitionResult],
file_context: str
) -> List[DefinitionResult]:
"""按文件接近度排序 (V1: 路径接近度)"""
def proximity_score(result):
# 1. 同目录最高分
if os.path.dirname(result.file_path) == os.path.dirname(file_context):
return 100
# 2. 共同路径前缀长度
common = os.path.commonpath([result.file_path, file_context])
return len(common)
return sorted(results, key=proximity_score, reverse=True)
```
**V2 增强计划** (基于 import graph 距离):
```python
def rank_by_import_distance(
results: List[DefinitionResult],
file_context: str,
import_graph: Dict[str, Set[str]]
) -> List[DefinitionResult]:
"""按 import graph 距离排序 (V2)"""
def import_distance(result):
# BFS 计算最短 import 路径
return bfs_shortest_path(
import_graph,
file_context,
result.file_path
)
# 组合: 0.6 * import_distance + 0.4 * path_proximity
return sorted(results, key=lambda r: (
0.6 * import_distance(r) +
0.4 * (100 - proximity_score(r))
))
```
### 5.4 参考实现: `get_file_symbols()`
**位置**: `src/codexlens/storage/global_index.py`
```python
def get_file_symbols(self, file_path: str | Path) -> List[Symbol]:
"""
获取指定文件中定义的所有符号。
Args:
file_path: 文件路径 (相对或绝对)
Returns:
按行号排序的符号列表
"""
file_path_str = str(Path(file_path).resolve())
with self._lock:
conn = self._get_connection()
rows = conn.execute(
"""
SELECT symbol_name, symbol_kind, file_path, start_line, end_line
FROM global_symbols
WHERE project_id = ? AND file_path = ?
ORDER BY start_line
""",
(self.project_id, file_path_str),
).fetchall()
return [
Symbol(
name=row["symbol_name"],
kind=row["symbol_kind"],
range=(row["start_line"], row["end_line"]),
file=row["file_path"],
)
for row in rows
]
```
---
## 六、实现计划
### Phase 0: 基础设施 (16h)
| 任务 | 工时 | 说明 |
|------|------|------|
| 修复 `search_references` schema | 4h | 兼容两种 schema |
| 新增 `GlobalSymbolIndex.get_file_symbols()` | 4h | 文件符号查询 (见 5.4) |
| 新增 `RelationshipQuery` 类 | 6h | 有向调用查询 |
| 关系类型规范化层 | 2h | `calls``call` |
### Phase 1: API 层 (48h)
| 任务 | 工时 | 复杂度 |
|------|------|--------|
| `find_definition()` | 4h | S |
| `find_references()` | 8h | M |
| `workspace_symbols()` | 4h | S |
| `get_hover()` | 4h | S |
| `file_context()` | 16h | L |
| `semantic_search()` | 12h | M |
### Phase 2: 测试与文档 (16h)
| 任务 | 工时 |
|------|------|
| 单元测试 (≥80%) | 8h |
| API 文档 | 4h |
| 示例代码 | 4h |
### 关键路径
```
Phase 0.1 (schema fix)
Phase 0.2 (file symbols) → Phase 1.5 (file_context)
Phase 1 (其他 API)
Phase 2 (测试)
```
---
## 七、测试策略
### 7.1 单元测试
```python
# test_global_index.py
def test_get_file_symbols():
index = GlobalSymbolIndex(":memory:")
index.update_file_symbols(project_id=1, file_path="test.py", symbols=[...])
results = index.get_file_symbols("test.py")
assert len(results) == 3
# test_relationship_query.py
def test_outgoing_calls():
store = DirIndexStore(":memory:")
calls = store.get_outgoing_calls("src/auth.py", "login")
assert calls[0].relationship == "call" # 已规范化
```
### 7.2 Schema 兼容性测试
```python
def test_search_references_both_schemas():
"""测试两种 schema 的引用搜索"""
# 旧 schema: files(path, ...)
# 新 schema: files(full_path, ...)
```
### 7.3 降级测试
```python
def test_semantic_search_without_vectors():
result = semantic_search(query="auth", mode="fusion")
assert result.vector_score is None
assert result.fusion_score > 0
```
---
## 八、使用示例
```python
from codexlens.api import (
file_context,
find_definition,
find_references,
semantic_search
)
# 1. 获取文件上下文
result = file_context(
project_root="/path/to/project",
file_path="src/auth/login.py",
format="brief"
)
print(result.summary)
# 2. 查找定义
definitions = find_definition(
project_root="/path/to/project",
symbol_name="UserService",
symbol_kind="class"
)
# 3. 语义搜索
results = semantic_search(
project_root="/path/to/project",
query="处理用户登录验证的函数",
mode="fusion"
)
```
---
## 九、CCW 集成
| codexlens API | CCW MCP Tool |
|---------------|--------------|
| `file_context()` | `codexlens_file_context` |
| `find_definition()` | `codexlens_find_definition` |
| `find_references()` | `codexlens_find_references` |
| `workspace_symbols()` | `codexlens_workspace_symbol` |
| `get_hover()` | `codexlens_get_hover` |
| `semantic_search()` | `codexlens_semantic_search` |
---
## 十、分析来源
| 工具 | Session ID | 贡献 |
|------|------------|------|
| Gemini | `1768618654438-gemini` | 架构评审、设计缺陷、融合策略 |
| Codex | `1768618658183-codex` | 组件复用、复杂度估算、任务分解 |
| Gemini | `1768620615744-gemini` | 最终评审、改进建议、APPROVED |
---
## 十一、版本历史
| 版本 | 日期 | 变更 |
|------|------|------|
| 1.0 | 2025-01-17 | 初始版本,合并多文档 |
| 1.1 | 2025-01-17 | 应用 Gemini 评审改进: V1 限制说明、策略映射、消歧义增强、参考实现 |