Skip to content

Commit 888f5cb

Browse files
invalidclaude
andcommitted
feat(v0.2.5): add variable tracking, line-level references, and symbol_refs
- Add module-level variable tracking (const/static/let/var) for all 8 languages (TypeScript, JavaScript, Python, Go, Rust, Java, C, C++) - Add line-level cross-file reference tracking (SymbolRef with import_line + use_lines) - Add scan_symbol_uses to scanner for identifier-level usage detection - Upgrade query engine: --type variable filter, CallerRef with line info - Fix collect_module_stats double-counting bug in slicer.rs - Fix update command to compute symbol_refs during incremental updates - Add 25 integration tests (variable_compat.rs) covering all languages + pipeline - Restore 3 deleted query tests (query_dependencies, format_symbol_results) - Update plugin version 0.2.4 → 0.2.5, CLI version 0.2.0 → 0.2.5 - Update README, query command prompt, and SKILL.md routing table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8ea3017 commit 888f5cb

26 files changed

Lines changed: 1179 additions & 50 deletions

README.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ AST-based code graph mapping plugin for [Claude Code](https://docs.anthropic.com
1010
- **AST 解析 / AST Parsing** — 使用 tree-sitter 原生绑定进行精确的结构分析,非正则猜测 / Uses tree-sitter native bindings for accurate structural analysis, no regex guessing
1111
- **多语言支持 / Multi-Language** — TypeScript, JavaScript, Python, Go, Rust, Java, C, C++
1212
- **智能切片 / Smart Slicing** — 项目概览 (~500 tokens) + 按模块切片 (~2-5k tokens),替代全量源码 (~200k+) / Project overview (~500 tokens) + per-module slices (~2-5k tokens) instead of full source (~200k+)
13+
- **变量追踪 / Variable Tracking** — 追踪模块级 const/static/let/var 声明,支持按 `--type variable` 查询 / Tracks module-level const/static/let/var declarations, queryable with `--type variable`
14+
- **行号级引用 / Line-Level References** — 跨文件引用精确到 import 行号 + 使用行号,而非仅文件名 / Cross-file references pinpoint import line + usage lines, not just file names
1315
- **增量更新 / Incremental Updates** — 基于文件哈希比较检测变更,仅重新解析修改的文件 / File hash comparison detects changes; only re-parses modified files
1416
- **影响分析 / Impact Analysis** — 重构前查看哪些模块会受影响 / See what's affected before you refactor
1517
- **自动触发 / Auto-Triggering** — Skill 根据对话上下文自动激活 / Skills activate automatically based on your conversation context
@@ -170,8 +172,8 @@ cd rust-cli && cargo test
170172
# 2. 提交并打 tag,CI 自动构建并发布 / Commit, tag, and let CI build & release
171173
cd ..
172174
git add .
173-
git commit -m "release: v0.2.2"
174-
git tag v0.2.2
175+
git commit -m "release: v0.2.5"
176+
git tag v0.2.5
175177
git push origin main --tags
176178
# GitHub Actions 会自动为所有平台构建并创建 Release
177179
# GitHub Actions will automatically build for all platforms and create a Release
@@ -217,7 +219,7 @@ CodeMap/
217219
│ │ ├── path_utils.rs # 共享路径工具函数
218220
│ │ ├── traverser.rs # 文件遍历与语言检测
219221
│ │ └── languages/ # 语言适配器 (8 种)
220-
│ └── tests/ # 集成测试 (286 tests)
222+
│ └── tests/ # 集成测试 (127 tests)
221223
├── README.md
222224
└── LICENSE # MIT
223225
```
@@ -234,7 +236,7 @@ All commands run via `codegraph <command>` (pre-compiled binary, no Node.js requ
234236
|---------|-------------|
235237
| `scan <dir>` | 全量 AST 扫描,生成 `.codemap/` 图谱和切片 / Full AST scan, generates `.codemap/` with graph + slices |
236238
| `status [dir]` | 显示图谱元信息(文件数、模块、上次扫描时间)/ Show graph metadata (files, modules, last scan time) |
237-
| `query <symbol>` | 按名称搜索函数、类、类型 / Search for functions, classes, types by name |
239+
| `query <symbol>` | 按名称搜索函数、类、类型、变量 / Search for functions, classes, types, variables by name |
238240
| `slice [module]` | 输出项目概览或指定模块切片(JSON)/ Output project overview or a specific module slice as JSON |
239241
| `update [dir]` | 增量更新——仅重新解析变更的文件 / Incremental update — re-parse only changed files |
240242
| `impact <target>` | 分析修改目标会影响哪些模块 / Analyze which modules are affected by changing a target |
@@ -306,14 +308,14 @@ The `codemap` skill auto-activates based on conversation context and intelligent
306308

307309
| 语言 / Language | 扩展名 / Extensions | 提取结构 / Extracted Structures |
308310
|----------|-----------|---------------------|
309-
| TypeScript | `.ts`, `.tsx` | 函数、导入、导出、类、接口、类型别名 / Functions, imports, exports, classes, interfaces, type aliases |
310-
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | 函数、导入、导出、类 / Functions, imports, exports, classes |
311-
| Python | `.py` | 函数(含装饰器)、导入、`__all__` 导出、类 / Functions (decorated), imports, `__all__` exports, classes |
312-
| Go | `.go` | 函数、方法(含接收者)、导入、导出名、结构体、类型声明 / Functions, methods (with receiver), imports, exported names, structs, type specs |
313-
| Rust | `.rs` | 函数、impl 方法、use 声明、pub 导出、结构体、枚举、trait / Functions, impl methods, use declarations, pub exports, structs, enums, traits |
314-
| Java | `.java` | 方法、构造器、导入、public 导出、类、接口、枚举 / Methods, constructors, imports, public exports, classes, interfaces, enums |
315-
| C | `.c`, `.h` | 函数、`#include`、非 static 导出、结构体、枚举、typedef / Functions, `#include`, non-static exports, structs, enums, typedefs |
316-
| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp`, `.hh` | 限定函数名(`Class::method`)、include、类、结构体、命名空间 / Qualified functions (`Class::method`), includes, classes, structs, namespaces |
311+
| TypeScript | `.ts`, `.tsx` | 函数、导入、导出、类、接口、类型别名、变量(const/let)/ Functions, imports, exports, classes, interfaces, type aliases, variables (const/let) |
312+
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` | 函数、导入、导出、类、变量(const/let)/ Functions, imports, exports, classes, variables (const/let) |
313+
| Python | `.py` | 函数(含装饰器)、导入、`__all__` 导出、类、模块级变量 / Functions (decorated), imports, `__all__` exports, classes, module-level variables |
314+
| Go | `.go` | 函数、方法(含接收者)、导入、导出名、结构体、类型声明、变量(var/const)/ Functions, methods (with receiver), imports, exported names, structs, type specs, variables (var/const) |
315+
| Rust | `.rs` | 函数、impl 方法、use 声明、pub 导出、结构体、枚举、trait、变量(const/static)/ Functions, impl methods, use declarations, pub exports, structs, enums, traits, variables (const/static) |
316+
| Java | `.java` | 方法、构造器、导入、public 导出、类、接口、枚举、静态字段 / Methods, constructors, imports, public exports, classes, interfaces, enums, static fields |
317+
| C | `.c`, `.h` | 函数、`#include`、非 static 导出、结构体、枚举、typedef、全局变量 / Functions, `#include`, non-static exports, structs, enums, typedefs, global variables |
318+
| C++ | `.cpp`, `.cc`, `.cxx`, `.hpp`, `.hh` | 限定函数名(`Class::method`)、include、类、结构体、命名空间、全局变量 / Qualified functions (`Class::method`), includes, classes, structs, namespaces, global variables |
317319

318320
---
319321

@@ -341,7 +343,7 @@ Scanning produces a `.codemap/` directory inside the target project:
341343
```bash
342344
cd rust-cli
343345
cargo test
344-
# 286 tests, all passing
346+
# 127 tests, all passing
345347
```
346348

347349
## 许可证 / License

ccplugin/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codemap",
3-
"version": "0.2.4",
3+
"version": "0.2.5",
44
"description": "AST-based code graph mapping plugin for Claude Code — scan once, persist structural graph, load compact slices to save ~95% tokens",
55
"author": {
66
"name": "killvxk",

ccplugin/commands/query.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
---
2-
description: 在代码图谱中查询函数、类、类型的定义位置和调用关系
2+
description: 在代码图谱中查询函数、类、类型、变量的定义位置和调用关系
33
arguments:
44
- name: symbol
5-
description: 要查询的符号名称(函数名、类名、类型名)
5+
description: 要查询的符号名称(函数名、类名、类型名、变量名
66
required: true
77
- name: type
8-
description: "过滤符号类型: function, class, type"
8+
description: "过滤符号类型: function, class, type, variable"
99
required: false
1010
---
1111

1212
# CodeMap Query — 符号查询
1313

14-
在代码图谱中搜索函数、类、类型或模块的定义和关联信息
14+
在代码图谱中搜索函数、类、类型、变量或模块的定义和关联信息
1515

1616
## 执行步骤
1717

@@ -24,10 +24,10 @@ arguments:
2424
### 2. 展示结果
2525

2626
向用户展示:
27-
- 符号类型(函数/类/接口/类型别名)
27+
- 符号类型(函数/类/接口/类型别名/变量
2828
- 定义位置(文件:行号)
29-
- 函数签名(如果是函数)
30-
- 调用者和被调用者
29+
- 函数签名(如果是函数)或变量声明(如果是变量)
30+
- 调用者和被调用者(含行号级引用信息)
3131
- 所属模块
3232

3333
### 3. 深入查看

ccplugin/skills/codemap/SKILL.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ description: >
99
影响分析, 重构, scan, load, query, impact, update, prompts, codemap, code graph,
1010
understand codebase, project overview, code structure, 了解代码, 开始工作,
1111
查找函数, 哪里定义, 谁调用了, 影响范围, 依赖分析, 更新图谱, 刷新,
12+
变量, 常量, variable, const, static, 全局变量, 模块变量,
1213
CLAUDE.md, 使用规范, 注入规则.
1314
---
1415

@@ -44,7 +45,8 @@ ls .codemap/graph.json 2>/dev/null && echo "CODEMAP_EXISTS" || echo "NO_CODEMAP"
4445
|----------|----------|
4546
| 会话刚开始 / 想了解项目 / 无特定需求 | 执行 `/codemap:load` 加载概览 |
4647
| 提到特定模块名 | 执行 `/codemap:load <模块名>` |
47-
| 问某个函数/类/类型在哪、谁调用了 | 执行 `/codemap:query <符号名>` |
48+
| 问某个函数/类/类型/变量在哪、谁调用了 | 执行 `/codemap:query <符号名>` |
49+
| 查询变量/常量定义 | 执行 `/codemap:query <变量名> --type variable` |
4850
| 谈到重构、改动影响、风险评估 | 执行 `/codemap:impact <目标>` |
4951
| 说代码改了、图谱过期、要刷新 | 执行 `/codemap:update` |
5052
| 要重新全量扫描 | 执行 `/codemap:scan` |

rust-cli/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust-cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "codegraph"
3-
version = "0.2.0"
3+
version = "0.2.5"
44
edition = "2021"
55

66
[[bin]]

rust-cli/src/commands/query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::path::PathBuf;
55
pub struct QueryArgs {
66
/// Symbol or module name to query
77
pub symbol: String,
8-
/// Filter by type: function, class, or type
8+
/// Filter by type: function, class, type, or variable
99
#[arg(long)]
1010
pub r#type: Option<String>,
1111
/// Project directory

rust-cli/src/commands/update.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,32 @@ pub fn run(args: UpdateArgs) {
125125
let lang_imports = adapter.extract_imports(&tree, content);
126126
let lang_exports = adapter.extract_exports(&tree, content);
127127
let lang_classes = adapter.extract_classes(&tree, content);
128+
let lang_variables = adapter.extract_variables(&tree, content);
128129
let lines = content.iter().filter(|&&b| b == b'\n').count() as u32 + 1;
129130

130131
let functions = crate::scanner::convert_functions(&lang_functions);
131132
let classes = crate::scanner::convert_classes(&lang_classes);
132133
let types = crate::scanner::convert_types(&lang_classes, lang);
133134
let imports = crate::scanner::convert_imports(&lang_imports);
134135
let exports = crate::scanner::convert_exports(&lang_exports);
136+
let variables = crate::scanner::convert_variables(&lang_variables);
137+
138+
// 构建 symbol_refs(与 scan_project 一致)
139+
let imported_symbols: std::collections::HashSet<String> = imports.iter()
140+
.flat_map(|imp| imp.symbols.iter().cloned())
141+
.collect();
142+
let symbol_uses = crate::scanner::scan_symbol_uses(&tree, content, &imported_symbols);
143+
let mut symbol_refs: std::collections::BTreeMap<String, crate::graph::SymbolRef> = std::collections::BTreeMap::new();
144+
for imp in &imports {
145+
for sym in &imp.symbols {
146+
let use_lines = symbol_uses.get(sym).cloned().unwrap_or_default();
147+
symbol_refs.insert(sym.clone(), crate::graph::SymbolRef {
148+
symbol: sym.clone(),
149+
import_line: imp.import_line,
150+
use_lines,
151+
});
152+
}
153+
}
135154

136155
let module_name = crate::scanner::detect_module_name(&abs_path, &root);
137156
let hash = new_hashes[rel_path].clone();
@@ -146,9 +165,11 @@ pub fn run(args: UpdateArgs) {
146165
functions,
147166
classes,
148167
types,
168+
variables,
149169
imports,
150170
exports,
151171
is_entry_point: crate::graph::is_entry_point(&abs_path),
172+
symbol_refs,
152173
},
153174
);
154175
}

rust-cli/src/differ.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,11 @@ mod tests {
239239
functions: vec![],
240240
classes: vec![],
241241
types: vec![],
242+
variables: vec![],
242243
imports: vec![],
243244
exports: vec![],
244245
is_entry_point: false,
246+
symbol_refs: std::collections::BTreeMap::new(),
245247
}
246248
}
247249

@@ -387,6 +389,7 @@ mod tests {
387389
source: "../utils/helper".to_string(),
388390
symbols: vec![],
389391
is_external: false,
392+
import_line: 0,
390393
}];
391394
graph.files.insert("src/auth/login.ts".to_string(), auth_file);
392395

rust-cli/src/graph.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub struct ImportInfo {
2222
pub symbols: Vec<String>,
2323
#[serde(rename = "isExternal")]
2424
pub is_external: bool,
25+
#[serde(rename = "importLine", default)]
26+
pub import_line: u32,
2527
}
2628

2729
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -43,6 +45,25 @@ pub struct TypeInfo {
4345
pub end_line: u32,
4446
}
4547

48+
#[derive(Debug, Clone, Serialize, Deserialize)]
49+
pub struct VariableInfo {
50+
pub name: String,
51+
pub kind: String, // "const" | "static" | "let" | "var"
52+
#[serde(rename = "startLine")]
53+
pub start_line: u32,
54+
#[serde(rename = "isExported", default)]
55+
pub is_exported: bool,
56+
}
57+
58+
#[derive(Debug, Clone, Serialize, Deserialize)]
59+
pub struct SymbolRef {
60+
pub symbol: String,
61+
#[serde(rename = "importLine", default)]
62+
pub import_line: u32,
63+
#[serde(rename = "useLines", default)]
64+
pub use_lines: Vec<u32>,
65+
}
66+
4667
#[derive(Debug, Clone, Serialize, Deserialize)]
4768
pub struct FileEntry {
4869
pub language: String,
@@ -52,10 +73,14 @@ pub struct FileEntry {
5273
pub functions: Vec<FunctionInfo>,
5374
pub classes: Vec<ClassInfo>,
5475
pub types: Vec<TypeInfo>,
76+
#[serde(default)]
77+
pub variables: Vec<VariableInfo>,
5578
pub imports: Vec<ImportInfo>,
5679
pub exports: Vec<String>,
5780
#[serde(rename = "isEntryPoint")]
5881
pub is_entry_point: bool,
82+
#[serde(rename = "symbolRefs", default)]
83+
pub symbol_refs: BTreeMap<String, SymbolRef>,
5984
}
6085

6186
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -81,6 +106,8 @@ pub struct GraphSummary {
81106
pub total_functions: u32,
82107
#[serde(rename = "totalClasses")]
83108
pub total_classes: u32,
109+
#[serde(rename = "totalVariables", default)]
110+
pub total_variables: u32,
84111
pub languages: HashMap<String, u32>,
85112
pub modules: Vec<String>,
86113
#[serde(rename = "entryPoints")]
@@ -153,6 +180,7 @@ pub fn create_empty_graph(project_name: &str, root_dir: &str) -> CodeGraph {
153180
total_files: 0,
154181
total_functions: 0,
155182
total_classes: 0,
183+
total_variables: 0,
156184
languages: HashMap::new(),
157185
modules: vec![],
158186
entry_points: vec![],

0 commit comments

Comments
 (0)