1broseidon/cymbal
GitHub: 1broseidon/cymbal
一款基于 tree-sitter 的语言无关代码索引与符号导航 CLI 工具,解决代码理解与变更影响分析的搜索精度与效率问题。
Stars: 160 | Forks: 17
# cymbal
[](https://github.com/1broseidon/cymbal/stargazers)
[](https://pkg.go.dev/github.com/1broseidon/cymbal)
[](https://goreportcard.com/report/github.com/1broseidon/cymbal)
[](https://github.com/1broseidon/cymbal/releases/latest)
快速、语言无关的代码索引器和符号导航器,基于 [tree-sitter](https://tree-sitter.github.io/) 构建。
cymbal 将你的代码库解析为本地 SQLite 索引,然后提供即时符号搜索、交叉引用、影响分析和作用域差异 —— 全部通过命令行完成。专为 AI 代理、编辑器插件或直接从终端调用而设计。
## 安装
Homebrew (macOS / Linux):
```
brew install 1broseidon/tap/cymbal
```
Windows (PowerShell):
```
irm https://raw.githubusercontent.com/1broseidon/cymbal/main/install.ps1 | iex
```
卸载(默认保留索引数据):
```
# 移除二进制文件和 PATH 条目,保留 SQLite 索引
irm https://raw.githubusercontent.com/1broseidon/cymbal/main/uninstall.ps1 | iex
# 同时移除所有 SQLite 索引
& ([scriptblock]::Create((irm https://raw.githubusercontent.com/1broseidon/cymbal/main/uninstall.ps1))) -Purge
```
Go(需要 CGO 配合 tree-sitter + SQLite):
```
CGO_CFLAGS="-DSQLITE_ENABLE_FTS5" go install github.com/1broseidon/cymbal@latest
```
或从 [releases](https://github.com/1broseidon/cymbal/releases) 下载二进制文件。
### Docker
无需本地 Go 工具链或 CGO 设置 —— 可直接从预构建容器运行 cymbal(支持 linux/amd64 和 arm64):
```
docker pull ghcr.io/1broseidon/cymbal:latest
```
挂载任意仓库后,SQLite 索引默认位于容器内的 `/workspace/.cymbal/index.db`(通过 `CYMBAL_DB`):
```
# 索引一个仓库
docker run --rm -v /path/to/your/repo:/workspace ghcr.io/1broseidon/cymbal index .
# 查询它(索引持久化至 /path/to/your/repo/.cymbal/index.db)
docker run --rm -v /path/to/your/repo:/workspace ghcr.io/1broseidon/cymbal investigate handleAuth
# 如需覆盖数据库位置
docker run --rm -v /path/to/your/repo:/workspace -e CYMBAL_DB=/some/other/path.db ghcr.io/1broseidon/cymbal index .
```
如需固定特定版本:
```
docker pull ghcr.io/1broseidon/cymbal:v0.8.4
```
或自行构建镜像:
```
docker build -t cymbal .
# 或使用 docker compose(默认挂载当前目录):
docker compose run --rm cymbal index .
```
将 `.cymbal/` 添加到 `.gitignore` 以将索引排除在版本控制之外。
## 快速开始
定义一个 shell 别名,使每条命令都像原生二进制文件一样:
```
alias cymbal='docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal'
```
然后:
```
# 索引当前项目
cymbal index .
# 调查任意符号 — 一次调用,正确答案
cymbal investigate handleAuth # function → source + callers + impact
cymbal investigate UserModel # type → definition + members + references
cymbal trace handleAuth # downward call chain — what does it call?
# 或在使用控制时采用特定命令
cymbal search handleAuth # find a symbol
cymbal search "TODO" --text # full-text grep
cymbal show handleAuth # read source
cymbal outline internal/auth/handler.go # file structure
cymbal refs handleAuth # who calls this?
cymbal importers internal/auth # who imports this package?
cymbal impact handleAuth # what breaks if I change this?
cymbal diff handleAuth main # git diff scoped to a function
cymbal context handleAuth # bundled: source + types + callers + imports
cymbal ls # file tree
```
索引会在首次使用时自动构建 —— 无需手动执行 `cymbal index .`。后续查询会自动增量刷新(无变更时约 2ms)。
## 命令
| 命令 | 功能 |
|---------|-------------|
| `investigate` | **从这里开始。** 适应性探索 —— 单次调用,合适形态 |
| `structure` | 结构概览 —— 入口点、热区、中央包 |
| `trace` | 向下调用图 —— 该符号调用了什么? |
| `index` | 解析并索引目录 |
| `ls` | 文件树、仓库列表或 `--stats` 概览 |
| `search` | 符号搜索(或 `--text` 用于 grep)。支持 `--path`、`--exclude` |
| `show` | 显示符号的源代码。`--all` 显示所有匹配项 |
| `outline` | 列出文件中的所有符号 |
| `refs` | 查找引用/调用位置。`--file` 按路径限定范围 |
| `importers` | 反向导入查找 —— 谁导入了这个? |
| `impls` | 实现/遵循/扩展该符号的类型。`--of ` 用于反向查询 |
| `impact` | 传递级调用者 —— 哪些内容受变更影响? |
| `diff` | 限定在符号行范围的 Git 差异 |
| `context` | 捆绑视图:源码 + 类型 + 调用者 + 导入 |
| `hook` | 代理集成钩子 —— `nudge`、`remind`、`install ` |
接受符号的命令支持 **批量操作**:`cymbal investigate Foo Bar Baz` 会在一次调用中运行所有三个命令。
所有命令均支持 `--json` 以输出结构化数据。
## 代理集成
cymbal 被设计为 AI 代理的代码导航层。一次命令即可处理大多数调查 —— 特定命令作为备用出口,以便在需要更多控制时使用。
将其添加到代理的系统提示词中(例如 `CLAUDE.md`、`AGENTS.md` 或 MCP 工具描述)。
**原生安装:**
```
## 代码探索策略
Use `cymbal` CLI for code navigation — prefer it over Read, Grep, Glob, or Bash for code exploration.
- **New to a repo?**: `cymbal structure` — entry points, hotspots, central packages. Start here.
- **To understand a symbol**: `cymbal investigate ` — returns source, callers, impact, or members based on what the symbol is.
- **To understand multiple symbols**: `cymbal investigate Foo Bar Baz` — batch mode, one invocation.
- **To trace an execution path**: `cymbal trace ` — follows the call graph downward (what does X call, what do those call).
- **To assess change risk**: `cymbal impact ` — follows the call graph upward (what breaks if X changes).
- Before reading a file: `cymbal outline ` or `cymbal show `
- Before searching: `cymbal search ` (symbols) or `cymbal search --text` (grep, delegates to rg when available)
- To filter results: `cymbal search --path 'src/*' --exclude '*_test.go' `
- To see all definitions: `cymbal show --all ` or `cymbal refs --file context.go `
- Before exploring structure: `cymbal ls` (tree) or `cymbal ls --stats` (overview)
- To disambiguate: `cymbal show path/to/file.go:SymbolName` or `cymbal investigate file.go:Symbol`
- The index auto-builds on first use — no manual indexing step needed. Queries auto-refresh incrementally.
- All commands support `--json` for structured output.
```
**Docker(无需本地安装):**
```
## 代码探索策略
Use `cymbal` via Docker for code navigation — prefer it over Read, Grep, Glob, or Bash for code exploration.
Run all cymbal commands as: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal `
- **New to a repo?**: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal structure` — entry points, hotspots, central packages. Start here.
- **To understand a symbol**: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal investigate ` — returns source, callers, impact, or members based on what the symbol is.
- **To understand multiple symbols**: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal investigate Foo Bar Baz` — batch mode, one invocation.
- **To trace an execution path**: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal trace ` — follows the call graph downward (what does X call, what do those call).
- **To assess change risk**: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal impact ` — follows the call graph upward (what breaks if X changes).
- Before reading a file: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal outline ` or `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal show `
- Before searching: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal search ` (symbols) or add `--text` for grep
- Before exploring structure: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal ls` or `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal ls --stats`
- To disambiguate: `docker run --rm -v "$(pwd)":/workspace ghcr.io/1broseidon/cymbal investigate path/to/file.go:Symbol`
- The index auto-builds on first use — no manual indexing step needed. Queries auto-refresh incrementally.
- The SQLite index is stored at `.cymbal/index.db` inside the mounted repo (via `CYMBAL_DB`).
- All commands support `--json` for structured output.
```
### 代理钩子
提示有效,但随着上下文增长,代理会退回到使用 `grep`/`find`(参见 [issue #23](https://github.com/1broseidon/cymbal/issues/23))。Cymbal 提供两个小型、代理无关的钩子命令:
| 命令 | 功能 |
|---|---|
| `cymbal hook nudge` | 检查待执行的 shell 命令,若看起来像代码搜索,则发出简短系统消息建议 cymbal 等效命令。永不阻塞。 |
| `cymbal hook remind` | 打印可调节语气的提醒块,代理可在会话开始时或按需注入。 |
**Claude Code —— 一键安装:**
```
cymbal hook install claude-code # ~/.claude/settings.json
cymbal hook install claude-code --scope project # .claude/settings.json
cymbal hook uninstall claude-code # clean removal
```
安装程序是幂等的,会保留无关设置,并标记自身条目以便 `uninstall` 可精确移除。
**其他代理**(Cursor、Windsurf、aider、Cline、Continue、Zed、Codex/OpenAI Agents SDK 或任何可在预工具事件中调用 shell 的工具) —— 请参阅 [`docs/AGENT_HOOKS.md`](docs/AGENT_HOOKS.md) 获取复制粘贴代码片段。两个子命令通用;`nudge` 提供 `--format=claude-code|json|text`,`remind` 提供相同三种格式,因此每个集成只需一两行。
### 为何有效
追踪认证流程的代理通常会进行 15-20 次顺序工具调用:显示函数 → 阅读代码 → 猜测下一个函数 → 显示该函数 → 重复。每次调用消耗一个推理步骤(约 500 个 token)。三条命令可消除此过程:
| 命令 | 回答的问题 | 方向 |
|---|---|---|
| `investigate X` | “告诉我关于 X 的信息” | 适应性(源码 + 调用者 + 影响 或 成员) |
| `trace X` | “X 依赖什么?” | 向下(被调用者,深度 3) |
| `impact X` | “什么依赖于 X?” | 向上(调用者,深度 2) |
`investigate` 替代搜索 → 显示 → 引用。`trace` 替代 10 条以上的连续显示调用来跟踪调用链。两者结合可将 22 次调用简化为 4 次。
## 支持的语言
cymbal 当前解析并索引以下语言(使用 tree-sitter):
- Go
- Python(`.py`、`.pyw`)
- JavaScript(`.js`、`.jsx`、`.mjs`、`.cjs`)
- TypeScript(`.ts`、`.tsx`、`.mts`、`.cts`)
- Rust
- C / C++(`.c`、`.h`、`.cpp`、`.cc`、`.hpp`、`.cxx`、`.hxx`、`.hh`)
- C#
- Java
- Apex
- Ruby(`.rb`、`.rake`、`.gemspec`)
- Swift
- Kotlin(`.kt`、`.kts`)
- Scala(`.scala`、`.sc`)
- PHP
- Lua
- Bash / Shell
- YAML
- Elixir
- HCL / Terraform(`.tf`、`.hcl`、`.tfvars`)
- Protobuf
- Dart
cymbal 也识别用于分类和 CLI 路径启发式的其他文件类型,即使它们不可解析/索引:`Dockerfile`、`Makefile`、`Jenkinsfile`、`CMakeLists.txt`、JSON、TOML、Markdown、SQL、Vue、Svelte、Zig、Erlang、Haskell、OCaml、R 和 Perl。
添加语言需要 tree-sitter 语法和符号提取查询。
## 工作原理
1. **索引** —— tree-sitter 将每个文件解析为 AST。cymbal 提取符号(函数、类型、变量、导入)和引用(调用、类型使用),并使用 FTS5 全文搜索存储在 SQLite 中。每个仓库拥有独立的数据库,存储在 OS 缓存目录(Linux 上为 `~/.cache/cymbal/repos/<>/index.db`,macOS 上为 `~/Library/Caches/cymbal/repos/`,Windows 上为 `%LOCALAPPDATA%\cymbal\repos\`)。可通过 `--db <路径>` 或 `CYMBAL_DB` 环境变量覆盖。索引在首次查询时自动构建 —— 无需手动执行 `cymbal index .`。
2. **查询** —— 所有命令从当前仓库的 SQLite 索引读取。符号查找、交叉引用和导入图均为 SQL 查询。无需重新解析,无跨仓库数据泄漏。
3. **始终新鲜** —— 每次查询自动检查文件变更并预先重新索引。无需手动重新索引、无需监视守护进程、无需钩子。编辑文件后运行查询即可获得正确结果。mtime+size 快速路径在无变更时增加约 10-24ms;仅脏文件被重新解析。
## 基准测试
在与 ripgrep 的对比测试中,使用了三个真实仓库(gin、kubectl、fastapi)的 Go 和 Python 代码。完整测试套件位于 `bench/`。
```
go run ./bench setup # clone pinned corpus repos
go run ./bench run # run all benchmarks → bench/RESULTS.md
```
**速度** —— cymbal 查询在 9-27ms 内完成。无变更时的重新索引:8-20ms。
**准确度** —— 在 43 项检查中达到 100% 基准精确率/召回率。在 9 个困难消歧案例中达到 100% 规范 @1 排名。7/7 grep 陷阱规避测试通过。
**令牌效率** —— 对于目标查询,cymbal 比 ripgrep 使用的令牌更少(`FastAPI`:11k grep 命中 → 8 个 cymbal 结果;`Context`:915 → 5)。引用查询收益最大,因为 cymbal 返回语义调用位置,而非每个包含字符串的行。
**即时新鲜度** —— 查询自动检测并重新解析变更文件。无变更时开销约 10-23ms;修改 1 个文件后约 22-27ms;修改 5 个文件后约 33-43ms。删除的文件会自动清除。
**代理工作流** —— `cymbal investigate` 用 1 次调用替代 3 次独立的 ripgrep 调用(搜索 + 显示 + 引用)。典型节省:41-100% 的令牌用于聚焦符号。
## 用作库
```
CGO_CFLAGS="-DSQLITE_ENABLE_FTS5" go get github.com/1broseidon/cymbal@latest
```
导出五个包:
| 包 | 功能 |
|---------|-------------|
| `index` | 索引引擎、SQLite 存储及所有查询 API |
| `lang` | 统一语言注册表,包含名称、扩展名、特殊文件名及解析器可用性 |
| `parser` | 22 种语言的 Tree-sitter 解析 |
| `symbols` | 核心数据类型(Symbol、Import、Ref) |
| `walker` | 并发文件发现与语言检测 |
```
import (
"fmt"
"github.com/1broseidon/cymbal/index"
)
// Index a repo
stats, _ := index.Index("/path/to/repo", "", index.Options{})
fmt.Printf("%d files, %d symbols\n", stats.FilesIndexed, stats.SymbolsFound)
// Query — all functions take a dbPath and return typed results
dbPath, _ := index.RepoDBPath("/path/to/repo")
results, _ := index.SearchSymbols(dbPath, index.SearchQuery{Text: "handleAuth"})
inv, _ := index.Investigate(dbPath, "handleAuth")
trace, _ := index.FindTrace(dbPath, "handleAuth", 3, 50)
impact, _ := index.FindImpact(dbPath, "handleAuth", 2, 100)
refs, _ := index.FindReferences(dbPath, "handleAuth", 50)
```
```
import "github.com/1broseidon/cymbal/lang"
fmt.Println(lang.Default.Supported("typescript")) // true
fmt.Println(lang.Default.Known("dockerfile")) // true
fmt.Println(lang.Default.LangForFile("Dockerfile")) // "dockerfile"
fmt.Println(lang.Default.LangForFile("notes.toml")) // "toml"
```
完整 API 参考、流式模式和底层存储访问请参阅 [库指南](./docs/guide/library.md)。
## 文档
- [库指南](./docs/guide/library.md)
- [变更日志](./CHANGELOG.md)
## 许可证
[MIT](./LICENSE)
标签:AI集成, Docker, EVTX分析, Go语言, Homebrew, SQLite, Tree-sitter, 二进制发布, 云安全监控, 代码交叉引用, 代码分析, 代码导航, 代码导航工具, 代码搜索, 代码浏览, 代码理解, 代码索引, 代码索引工具, 代码解析, 凭证管理, 威胁情报, 安全防御评估, 差异分析, 开发者工具, 开源工具, 影响分析, 日志审计, 本地索引, 程序破解, 符号搜索, 符号查找, 编辑器插件, 请求拦截, 跨语言, 静态分析