nguyenminhduc9988/graphscout
GitHub: nguyenminhduc9988/graphscout
GraphScout 为 AI 编程代理提供带缓存的增量代码图索引,使其能直接查询代码结构而非读取整个文件。
Stars: 0 | Forks: 0
[](https://pypi.org/project/graphscout/) [](https://pypi.org/project/graphscout/) [](https://github.com/nguyenminhduc9988/graphscout/actions/workflows/ci.yml) [](https://pypi.org/project/graphscout/) [](LICENSE) [](#-mcp-wired-automatically) [](https://github.com/nguyenminhduc9988/graphscout/stargazers) [](https://github.com/nguyenminhduc9988/graphscout)
▲ Real captured CLI output, not mockups — every line comes from an actual
graphscout run on this repo.
每个代码库只需执行一次 `build`;之后,每次查询只会自动刷新自上次调用以来发生更改的文件(基于 mtime)。没有强制后台进程,没有外部数据库,也没有 API 密钥 —— 只需在 `~/.cache/graphscout` 下使用 JSON 缓存,并按需在内存中构建 SQLite FTS5 索引用于搜索。希望它始终保持最新且没有单次查询开销?运行 `graphscout watch` 即可。 曾以
codegraph-kit(代码库 codegraph)名称发布 —— 为避免与毫不相关且庞大得多的 colbymchenry/codegraph 混淆而重命名。缓存格式相同($CODEGRAPH_CACHE 仍然有效)。请参阅 客观对比,了解每款工具各自胜出的确切领域。
## 🆕 0.6.0 版本更新
六种基于图的新功能 —— 这些答案两个 codegraph 都无法提供,每一项都建立在 graphscout 已经提取的数据之上,而不是重新解析一次:
- **`metrics [query]`** —— 每个符号的复杂度卡片:**fan-in**(有多少地方调用它 —— 承载核心功能)、**fan-out**(有多少个不同的被调用者 —— 复杂度的代理指标)、进/出的引用/类型边,以及推断的函数体行数。带有名称时,显示单个符号的卡片;不带名称时,以两种方式对代码库进行排名 —— fan-out 最高(可能过大的函数)和 fan-in 最高(许多调用者依赖的中心节点)。
- **`dupes`** —— 跨文件的复制粘贴/高度相似的函数体。函数体会被标准化(去除注释、空格、大小写差异;移除声明行,因此函数体相同但名称不同的两个函数依然会被聚为一类)。调用图根本看不出这一点 —— 两个完全相同的辅助函数之间并不存在边。
- **`recent`** —— 最近 N 次提交修改过的文件中的符号。比 `diff`(需要两个明确的引用)更轻量:这是一个用于了解代码库近况的变动窗口视图,“最近有什么变化”。
- **`why `** —— 通过已解析的调用边,寻找从一个符号到另一个符号的最短调用链。这是关于双符号的“为什么 A 依赖 B”的问题,而 `impact`(从一个种子节点向外的无向影响范围)无法直接回答这个问题。
- **`tokens | ### 🔎 `explore` —— 一次调用,而非四次 匹配度最高的符号的原始源码 + 调用者/被调用者 + 多跳影响范围。Agent 实际需要的结构形式,而不是将 `sym → file → callers → Read` 串联起来。 | ### 🧠 排名全文搜索 内存级 SQLite FTS5(支持 bm25、前缀、多词搜索)—— 不是简单的子字符串扫描 —— 并且排除文档字符串节点,因此真正的符号不会被冗长的文本淹没。 | |
| ### 💥 多跳影响分析 在调用图上进行有深度限制的双向 BFS —— 体现变更的*实际*影响范围,而不是单跳的调用者/被调用者猜测。 | ### 🧪 从 diff 获取测试影响 `git diff --name-only \| graphscout affected --stdin` —— 通过解析的导入追踪此次更改会影响哪些测试。 | |
| ### 🙈 感知 `.gitignore` 的索引 通过 `git ls-files --exclude-standard` 进行路由 —— 完全按照 git 所见的方式处理嵌套的 `.gitignore` 和全局排除文件。硬编码的跳过项(`node_modules`、`dist` 等)始终适用。 | ### ⚡ 基于 mtime 的增量缓存 每个代码库只需执行一次 `build`;每次查询仅重新提取更改过的内容。无需数据库服务器,无需守护进程 —— `graphscout watch` 是可选的。 | |
| ### ⚙️ `exclude` / `include` / `extensions` 可选的 `graphscout.json` —— 强制重新包含 vendored 路径,丢弃冗余的生成代码,或将非标准后缀映射到支持的语言。 | ### 🔌 CLI *与* MCP 两种方式均可执行相同的查询 —— 从任何 Agent 执行 shell 命令,或者使用一条命令将 MCP 服务器接入 Claude Code、Codex、Gemini CLI、Cursor 和 Windsurf。 | |
| ### 🔬 符号级 `diff` `graphscout diff HEAD~5` —— 新增/移除/修改的**函数**,而不是代码行块。重命名显示为一个更改的符号。 | ### 🧹 死代码 `orphans` 在排除入口点/测试/带装饰器的处理器*并*进行文本交叉检查以寻找图遗漏的调用方式后,代码库中没有调用者的代码。 | |
| ### 🔥 `hotspots` —— 变更频率 x 连通性 频繁更改且处于结构中心的文件 —— 重构优先级,而不仅是代码行数的猜测。 | ### 🌐 `routes` —— 一次调用获取 API 表面 Flask/FastAPI/Django/Express/Gin/NestJS/Spring/ASP.NET/Actix/Rails/Laravel 路由检测,在索引的文件集上使用正则表达式。 | |
| ### 🩺 `doctor` + 后台 `daemon` 一条命令排查“为什么 X 回退了”,外加分离的 `daemon start`,确保无需前台终端也能保持图形最新。 | ### 📦 全局支持 `--json` 每个查询命令均支持用于脚本/CI 的 `--json`;面向 Agent 的默认设置依然是纯文本。 | |
| ### 📊 `metrics` —— 来自图的复杂度 Fan-in(核心承载节点)、fan-out(复杂度代理指标)、引用耦合度、函数体行数 —— 可针对单个符号或对整个代码库排名。提供单凭调用列表无法给出的信号。 | ### 🔗 `why` + `recent` + `tokens` `why a b` —— 从 A→B 的最短调用链。`recent` —— 最近 N 次提交触及的符号。`tokens name` —— 阅读前的函数体成本。 | ### 🗺️ `viz --kind=imports` 调用图可视化(Mermaid/DOT)现在还可以渲染**模块依赖图** —— 即 `cycles`/`affected`/`rdeps` 推理所用的结构图,并将其绘制出来。 |
📐 以 Mermaid 图表展示的相同 pipeline(点击展开)
``` flowchart LR A["build / ensure"] -->|"git ls-files --exclude-standard
(honors .gitignore)"| B["tree-sitter extraction
via graphify"] B --> C[("graph.json
+ mtime index
~/.cache/graphscout")] C --> D{"query"} D -->|explore| E["verbatim source
+ call edges
+ blast radius"] D -->|search| F["FTS5 ranked
symbol search"] D -->|impact / affected| G["multi-hop BFS
over call / import edges"] style E fill:#7ee7c7,color:#0d1117 style F fill:#a5b4fc,color:#0d1117 style G fill:#a5b4fc,color:#0d1117 ```
⚠️ 诚实的局限性(在适用时同样会打印在输出中)
- **未捕获动态分派** —— 调用边来自于静态 AST 分析;`getattr` 风格的调用需要借助 grep。 - **限定模块调用在图中可能不可见** —— `from mod import fn; fn()` 可以解析;同样常见的 `import mod; mod.fn()` 惯用法仅在模块上产生 `imports` 边,而不是在函数上产生 `calls` 边(这是 graphify 的局限性,而非 graphscout 的)。正是由于这个原因,`orphans` 会进行纯文本交叉检查;而 `callers`/`callees`/`impact` 没有这样做,因此对于以这种风格编写的代码库,它们统计的数值可能会偏低。 - **不受支持/特殊的语言**会回退到“直接阅读”。 - **`affected` 在多名称绝对导入上检测不足** —— `from pkg import a, b` 解析为包上的一条边,而不是按名称区分。相对导入和单名称绝对导入可以完全解析。 - **没有来自提取器的行范围** —— graphify 为每个符号记录起始行,而不是起始+结束行;`explore` 的代码片段结尾被推断为“同一文件中下一个符号之前的那一行”(上限为 60 行)。 - **`routes` 是一种正则表达式启发式方法**,而不是语义方法 —— 它可能匹配到注释或文档字符串中呈路由状的字符串,并且会漏掉通过数据驱动表或运行时计算的装饰器注册的路由。 - **`orphans`/`hotspots` 是启发式方法,而非绝对确定** —— 在删除“死”代码之前请进行验证(动态分派、反射和已发布库的外部调用者在静态图中看起来都是未被引用的),也不要过度关注仅仅因为无聊的原因(如配置文件、更新日志)而频繁变动的“热点”文件。 - **限制:** 每个代码库最多 5,000 个文件,每个文件 1 MB(会发出警告,而非静默处理);影响范围/impact 遍历在达到 400 个节点时停止(标记为 `(truncated)`)。
**如果 `graphscout` 为您的 Agent 节省了数千个 token,请点个 ⭐ —— 这是它唯一的营销预算。**
MIT © Duc Nguyen · 解析由 graphify(基于 tree-sitter)提供 · 为 Agent 而生,为人类审计
MIT © Duc Nguyen · 解析由 graphify(基于 tree-sitter)提供 · 为 Agent 而生,为人类审计
标签:AI编程助手, MCP协议, SOC Prime, 上下文缓存, 代码图谱, 代码导航, 开发工具, 逆向工具