内容
# 代码地图
本地优先的代码智能,为AI代理和人员提供**结构意识**,将代码图(LSP + 解析器)与语义向量搜索(veclite)相结合,通过CLI、MCP服务器和交互式终端UI进行公开。
> 处理代码?请先阅读 [AGENTS.md](./AGENTS.md) - 它是约定、架构和注意事项的来源。
代码地图回答grep和单个LSP调用无法回答的问题:*谁调用此函数,哪些测试涵盖它*,*更改此类型的爆炸半径是什么*,*查找类似身份验证的代码,然后显示调用它的所有内容*。它预先计算结构,然后提供狭窄的、结构化的答案 - 因此代理程序花费几个工具调用而不是几十个文件读取。
## 功能
- **结构代码图** - 文件、函数、类型、方法和测试作为节点;**调用**边(默认为基于名称,精确通过`go/types`与`--precise`)和**定义**边(文件→符号)。测试覆盖率通过遍历调用图到测试节点得出。存储在纯Go SQLite中,可离线查询。索引**Go**(stdlib `go/parser`,完整调用图),**TypeScript + JavaScript**(一个`typescript-language-server`,调用解析*跨* `.ts`↔`.js`边界),和**Python**(`pyright-langserver`)- LSP支持的语言始终提供符号+结构,加上**精确调用图**在`--precise`下,因此`callers`/`impact`/`hotspots`/`path`也适用于它们。结构标记(Vue/HTML/CSS/Docker)是下一个。语义搜索是语言无关的。
- **语义搜索** - 每个节点的源代码都嵌入(Ollama `nomic-embed-text`,768维)到[veclite](https://github.com/abdul-hamid-achik/veclite);向量+BM25混合搜索。
- **影响分析** - `impact`返回一个符号的定义站点,直接调用者,传递爆炸半径(更改影响的所有内容),以及哪些测试涵盖这些路径(标记未测试的代码)。
- **多项目注册** - 一个共享存储索引所有仓库;`projects`列出已索引的内容,任何查询都针对一个项目(从cwd解析,或`--path`)。
- **注释** - 将注释和外部数据(DB行来自mongosh/postgres,vidtrace/vecgrep查找结果...)固定到符号或调用路径;它们在重新索引时持续存在。图上的知识层用于代理程序(`annotate` / `annotations`,也在MCP上)。
- **精确调用解析** - 快速基于名称的图上匹配同名方法(`x.Close()`链接到*每个* `Close`)。一个`codemap index --precise`解析每个调用到它实际调用的方法,并使**每个**查询 - 调用者,被调用者,影响,热点,路径 - 精确一次,无需每个查询标志(例如,一个`Close`方法,名称匹配归因于71个调用者,仅显示其实际调用者)。它是跨语言的统一精确解析通道:一个进程内,纯Go `go/types`通道用于**Go**,和LSP语言的`callHierarchy`用于**LSP语言**(TypeScript,JavaScript,Python - 没有基于名称的调用边,所以`--precise`是它们拥有调用图的全部原因)。选择加入且附加(基于名称的保持为Go的默认);Go通道在`go`工具链或模块不可用时降级为基于名称的**并带有注释**。
- **增量** - 基于哈希的重新索引;嵌入配置文件守护进程在提供者/模型/维度更改时强制重新构建,而不是破坏向量空间。
- **三个表面,一个存储** - 一个Cobra **CLI**(带有`--json`用于代理程序),一个stdio **MCP服务器**,和一个**studio** TUI用于人类。
- **图分析** - `hotspots`(中心),`orphans`(死代码候选),和`path`(两个符号之间的最短调用路径)。
- **本地优先和私有** - 所有内容都在您的机器上运行;无需云,无需上传。
- **单个二进制** - 纯Go,`CGO_ENABLED=0`,交叉编译并通过Homebrew发布。
## studio(TUI)
`codemap studio`打开一个交互式,全屏的代码浏览器(Charm v2 - Bubble Tea / Lip Gloss / Bubbles)。使用`1` - `4`或`tab`切换标签;使用`↑` / `↓`导航。
```
codemap studio codemap · 509 nodes · 1849 edges · 35 files
1 Graph 2 Metrics 3 Impact 4 Search
中心 │ lspsrc.Extractor.Close
57 lspsrc.Extractor.Close │ Called by (57)
56 app.Session.Close │ ▸ main.runInit cmd/codemap/main.go:186
56 graph.Store.Close │ main.runIndex cmd/codemap/main.go:209
26 app.NewService │ Calls (9)
19 app.Open │ app.Session.Close internal/app/session.go:80
│ ⟩ func runInit(cmd *cobra.Command, ...) error
↑/↓ 中心 · → walk callers/calls · enter → impact · p precise · ctrl+c quit
```
完全限定的名称消除同名符号的歧义(上面的六个不同的`Close`方法),并预览所选节点的签名(`⟩ func runInit(...)`)。
- **图** - 调用图浏览器:左边的中心(最被引用的符号)作为跳转点,中间节点的调用者和被调用者在右边。按`→`聚焦右侧面板并**遍历图** - `enter`重新聚焦调用者/被调用者,以便您可以遍历调用链;`backspace`步骤返回;`s`读取所选符号的**源代码**,在可滚动的叠加层中,无需离开工作室。
- **指标** - 概览仪表盘:计数和条形图(按种类/语言)位于左侧;调用图的两个极端位于右侧 - 顶部中心(最被引用)和死代码候选(无调用者)。两个列表都是可导航的 - `enter`深入一行到影响,`ctrl+s`读取其源代码。
- **影响** - 输入一个符号,查看其调用者,爆炸半径和哪些测试涵盖它。
- **搜索** - 按含义进行语义搜索,在没有嵌入的情况下回落到快速名称搜索(因此即使没有Ollama也适用)。
## 安装
### Homebrew(推荐)
```bash
brew install abdul-hamid-achik/tap/codemap
```
### 先决条件
- **Go 1.25+** (仅用于从源代码构建)
- **[Ollama](https://ollama.com)** 带有嵌入式模型:`ollama pull nomic-embed-text` (可选 - 没有它,索引仅限于结构)
- **[gopls](https://pkg.go.dev/golang.org/x/tools/gopls)** - 可选,用于 `--lsp` 精确的Go结果
- 可选: **[Task](https://taskfile.dev)** 用于开发工作流程
**语言** - 结构+语义搜索适用于所有这些;精确的调用图(`callers`/`callees`/`impact`/`hotspots`/`path`)需要`--precise`:
| 语言 | 如何 | 扩展 | 调用图 |
|---|---|---|---|
| **Go** | 内置 `go/parser` (+ `go/types` 用于 `--precise`) | `.go` | 默认基于名称;精确使用 `--precise` |
| **TypeScript / JavaScript** | `typescript-language-server` (一个服务器,JSX/TSX感知,解析 `.ts`↔`.js` 边界) | `.ts` `.tsx` `.js` `.jsx` `.mjs` `.cjs` | 仅 `--precise` |
| **Python** | `pyright-langserver` | `.py` | 仅 `--precise` |
语言服务器在安装时自动启用 - 运行 [`codemap doctor`](docs/cli.md) 查看检测到的服务器,或使用 `--no-lsp` 跳过。结构标记(Vue/HTML/CSS)正在计划中;其他识别的语言被报告为跳过。语义搜索与语言无关。
### 从源代码
```bash
git clone https://github.com/abdul-hamid-achik/codemap
cd codemap
task build # → ./bin/codemap (或: go build ./cmd/codemap)
```
### Go 安装
```bash
go install github.com/abdul-hamid-achik/codemap/cmd/codemap@latest
```
## 快速开始
```bash
# 1. 注册和索引项目
codemap init # 注册当前目录
codemap index # 提取图 + 嵌入节点(增量)
codemap index --no-embed # 仅限结构(不需要Ollama)
codemap index --precise # 精确调用边(Go通过go/types;TS/JS/Python通过callHierarchy)
# 索引您的代码,而不是依赖项:node_modules, venv, vendor, dist, build, __pycache__, .git (以及任何点目录)默认跳过 - 可通过`exclude`配置
```
## 命令
| 命令 | 功能 |
|---|---|
| `init` / `index` / `status` | 注册,索引(增量;`--reindex`,`--no-embed`,`--no-lsp`,`--precise`),显示统计信息 |
| `doctor` | 检查环境 - 工具链,语言服务器,嵌入式 - 带有安装提示 |
| `projects` | 列出所有注册的项目及其索引大小 |
| `callers` / `callees` / `path` | 调用图导航(`--lsp` 调用者/被调用者获取精确的gopls结果) |
| `symbols` | 列出文件的符号(结构化替代读取它) |
| `find` | 按名称查找符号(离线) |
| `source` | 打印符号的源代码(签名后面的主体) |
| `docs` | 打印codemap的代理指南(`docs [topic]`) |
| `annotate` / `annotations` | 固定/列出符号或调用路径上的注释+外部数据 |
| `impact` | 符号的爆炸半径+测试覆盖率( `--depth`) |
| `hotspots` / `orphans` | 中心/死代码候选( `--top`) |
| `semantic` (别名 `search`)| 基于含义的搜索( `--top`) |
| `serve` | 运行MCP服务器(stdio) |
| `studio` | 打开交互式TUI |
所有查询命令都接受 `--json`。
## 准确性:基于名称与精确
codemap的图**默认基于名称** - 即时,离线,并容忍损坏的代码。它在**包内**精确解析调用(Go),但跨包方法调用如 `x.Close()` 链接到*每个*名为 `Close`的方法,因为解析接收者的类型需要类型检查器。codemap对此保持诚实 - 而不是隐藏它:`callers`/`callees`/`impact`标志名称解析为多个定义,`hotspots`标记名称冲突膨胀。
**要获取精确的图,请使用 `codemap index --precise`** (Go)。它运行进程内,纯Go `go/types` 通道,解析每个调用到它实际调用的方法,并**替换**基于名称的调用边 - 因此*每个*查询(`callers`,`callees`,`impact`,`hotspots`,`path`)一次变得精确,无需每个查询标志。在codemap存储库本身上,这会折叠`Close`/`Error`扇出(例如,一个`Close`方法,名称匹配归因于71个调用者,降至其实际〜12),并将`hotspots`从名称冲突噪声变为真正的中心。要求和保证:
- 需要`go`工具链和可构建的模块。无法类型检查的包保持其基于名称的边(每个包降级);没有`go`/`go.mod`的项目完全回落 **并带有注释** - 永远不是硬错误,永远不会比基于名称的更糟糕。
- 纯粹是附加和选择加入:没有`--precise`,索引是字节对字节的快速基于名称路径。
- 接口调度是静态不可解的,因此精确的边指向接口方法,而不是具体的实现者。
**对于TypeScript, `--precise` 是 *仅有的* 调用边的源**。基于名称的通道提取TS结构(类,方法,函数)但不调用,因此普通的`index`给TS没有调用图;`index --precise`驱动`typescript-language-server` `callHierarchy`精确解析它们,并且相同的`callers`/`callees`/`impact`/`hotspots`/`path`查询然后适用于TS而无需它们自己的标志。需要`typescript-language-server`在`PATH`上。
对于一次性精确答案*而无需*重新索引,`callers`/`callees`也接受 `--lsp` (gopls `callHierarchy`),同样,如果gopls无法解析,则降级为基于名称并带有注释。
`orphans` 查找调用图的死点。它通过*值*连接的函数 - 表中的处理程序,如cobra的`RunE: runInit`,回调传递给注册器 - 因此这些不会标记为死(Go)。它仍然无法看到通过接口调度或反射到达的调用者,因此将其输出视为*候选*,而非证明。
## 从代理(MCP)使用它
codemap是一个stdio MCP服务器。注册 `codemap serve` 与您的代理 - 大多数CLI都有一个一行代码:
```bash
claude mcp add codemap -- codemap serve # Claude Code (添加 --scope user 用于所有项目)
codex mcp add codemap -- codemap serve # OpenAI Codex
copilot mcp add codemap -- codemap serve # GitHub Copilot CLI
```
对于任何其他MCP客户端,请在其配置中添加stdio服务器(键可能是 `mcpServers` , `mcp` 或 `context_servers`):
```json
{
"mcpServers": {
"codemap": { "command": "codemap", "args": ["serve"] }
}
}
```
连接后,代理可以调用 `codemap_docs` 自学工具和工作流程。
工具(19):`codemap_init`,`codemap_index`,`codemap_status`,`codemap_doctor`,`codemap_semantic`,`codemap_callers`,`codemap_callees`,`codemap_impact`,`codemap_hotspots`,`codemap_orphans`,`codemap_path`,`codemap_symbols`,`codemap_find`,`codemap_source`,`codemap_projects`,`codemap_docs`,`codemap_annotate`,`codemap_annotations`,`codemap_unannotate`。每个都接受可选的 `path` (项目目录)并返回JSON。 `codemap_callers` / `codemap_callees` 接受 `precise: true` 获取精确的gopls结果(Go); `codemap_source` 返回符号的主体; `codemap_projects` 列出已索引的内容; **`codemap_docs`** 返回代理指南,以便harness可以学习工具; **`codemap_annotate` / `codemap_annotations`** 将注释和数据(DB行,发现)固定到符号和调用路径上 - 图上的知识层(见下文)。
结果携带每个符号的**签名**(例如`func(s *Store)Hotspots(projectID int64,limit int)([]Hotspot,error)`)和**文档字符串**,因此代理程序理解调用者/被调用者/命中是什么以及它们的作用 - 而且同名符号很容易区分。
旗舰是`codemap_impact` - 一个调用返回符号的定义站点,调用者,传递爆炸半径和哪些测试涵盖这些路径,取代了许多文件读取。
## 配置
XDG样式,具有`CODEMAP_*`环境变量覆盖和生态系统回退:
```
$XDG_CONFIG_HOME/codemap/config.yaml # config (~/.config/codemap/…)
$XDG_DATA_HOME/codemap/ # graph DB, veclite, project registry
$XDG_CACHE_HOME/codemap/ # caches
```
如果`~/.codemap/`已经存在,则使用它(与vecgrep/noted的兼容)。使用`codemap init --local`保持仓库本地状态。优先级和所有键都记录在[AGENTS.md](./AGENTS.md)。覆盖路径使用`CODEMAP_CONFIG` / `CODEMAP_DATA`。
## 它如何适应生态系统
codemap 建立在 [veclite](https://github.com/abdul-hamid-achik/veclite) 之上,并与 [vecgrep](https://github.com/abdul-hamid-achik/vecgrep) (语义代码搜索)和 [noted](https://github.com/abdul-hamid-achik/noted) (代码注释)共享约定。代理可以组合它们:vecgrep/codemap 来 *查找* 按含义编码的代码,codemap 来了解 *哪些代码调用它* 和 *更改时破坏什么*。
## 文档
完整文档: **[docs/](./docs)** (VitePress)。设计原理: **[SPEC.md](./SPEC.md)**。
## 许可
[MIT](./LICENSE) © 2026 Abdul Hamid Achik