1broseidon/cymbal

GitHub: 1broseidon/cymbal

一款基于 tree-sitter 的语言无关代码索引与符号导航 CLI 工具,解决代码理解与变更影响分析的搜索精度与效率问题。

Stars: 160 | Forks: 17

# cymbal [![GitHub Stars](https://img.shields.io/github/stars/1broseidon/cymbal?style=social)](https://github.com/1broseidon/cymbal/stargazers) [![Go Reference](https://pkg.go.dev/badge/github.com/1broseidon/cymbal.svg)](https://pkg.go.dev/github.com/1broseidon/cymbal) [![Go Report Card](https://goreportcard.com/badge/github.com/1broseidon/cymbal)](https://goreportcard.com/report/github.com/1broseidon/cymbal) [![Latest Release](https://img.shields.io/github/v/release/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, 二进制发布, 云安全监控, 代码交叉引用, 代码分析, 代码导航, 代码导航工具, 代码搜索, 代码浏览, 代码理解, 代码索引, 代码索引工具, 代码解析, 凭证管理, 威胁情报, 安全防御评估, 差异分析, 开发者工具, 开源工具, 影响分析, 日志审计, 本地索引, 程序破解, 符号搜索, 符号查找, 编辑器插件, 请求拦截, 跨语言, 静态分析