内容
<p align="center">
<img src="docs/banner.svg" alt="Sens — 一个适用于 Claude Code 的项目索引" width="860">
</p>
<p align="center">
<a href="https://www.npmjs.com/package/sens-mcp"><img alt="npm 版本" src="https://img.shields.io/npm/v/sens-mcp?style=flat-square&color=cb3837&logo=npm"></a>
<a href="#license"><img alt="许可证:MIT" src="https://img.shields.io/badge/license-MIT-1a7f47?style=flat-square"></a>
<img alt="为 Claude Code 构建" src="https://img.shields.io/badge/built_for-Claude_Code-4f7cff?style=flat-square">
<img alt="MCP 服务器" src="https://img.shields.io/badge/MCP-server-7a5cff?style=flat-square">
<img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white">
<img alt="状态" src="https://img.shields.io/badge/status-early_development-e0a33d?style=flat-square">
</p>
<p align="center">
<b>让模型 <i>查询</i> 您的代码库,而不是阅读所有内容。</b><br>
更少的令牌,更干净的上下文,并在代码已存在或已死时提前通知。
</p>
---
## 为什么选择 Sens?
如果您在 **订阅** 上使用 Claude Code,您的痛苦不是每令牌计费,而是 **使用限制** 和 **上下文窗口充满**。每次代理打开 20 个文件只是为了定位,它就会消耗您的配额并扩大上下文(然后压缩并悄悄地丢失内存)。
Sens 保持项目 **索引** 的紧凑,并通过 **MCP** 将其提供给 Claude,这样模型会提出聚焦的问题而不是阅读所有内容:
> *"在哪里是 `login`?"* · *"谁使用它?"* · *"是否已经存在类似的东西?"* · *"这里有哪些死代码?"*
一个引擎,两种回报:
- 🪙 **更少的令牌 / 更干净的上下文** → 您的订阅持续时间更长,长时间会话保持清晰。
- 🧹 **更干净的代码** → 重用已存在的内容,而不是重复,并暴露死代码。
> [!NOTE]
> Sens **不是** 一个 "少写" 规则引擎(这就是 [ponytail](https://github.com/DietrichGebert/ponytail) 擅长的工作)。Sens 是底层的缺失部分:**项目知识**,使 "重用已存在的内容" 实际上起作用。它们是互补的。
## 目录
- [快速入门](#quick-start) · [Claude 获取的内容](#what-claude-gets-mcp-tools) · [斜杠命令](#slash-commands) · [CLI](#cli) · [仪表盘](#dashboard)
- [它真的有帮助吗?](#does-it-actually-help) · [工作原理](#how-it-works) · [配置](#configuration) · [死代码 - 请阅读此内容](#dead-code--read-this) · [路线图](#roadmap) · [许可证](#license)
## 快速入门
将 Sens 添加为 MCP 服务器。在您的项目的 `.mcp.json`(或 Claude Code 的 MCP 配置)中:
```json
{
"mcpServers": {
"sens": {
"command": "npx",
"args": ["-y", "sens-mcp", "mcp"]
}
}
}
```
或一次性为 **所有** 项目注册:
```bash
claude mcp add sens -s user -- npx -y sens-mcp mcp
```
就是这样。Claude Code 按需启动 Sens - 无需逐项目安装,无需手动运行服务器。然后只需自然地询问 Claude: *"使用 sens 映射此项目"*, *"有死代码吗?请用 sens 检查"*。
## Claude 获取的内容(MCP 工具)
| 工具 | 功能 | 替换 |
| --- | --- | --- |
| `project_map` | 仓库的一屏地图,包含每个文件的导出 | 阅读多个文件以定位 |
| `find_symbol` | 符号的定义位置(文件:行 + 签名) | `grep` |
| `who_uses` | 符号被使用的所有位置 | `grep` + 阅读 |
| `file_outline` | 文件的签名,不包含其主体 | 阅读整个文件 |
| `already_exists` | 是否已存在匹配关键字的项目 | 意外重复 |
| `dead_code` | 未使用的符号 / 导出(候选) | - |
| `file_dependencies` | 文件导入的内容和导入它的内容(导入图) | 在整个项目中搜索导入 |
## 工作规则
Sens 的 MCP 服务器还向 Claude 提供了一套简短的 **工作规则**,它在编写或更改代码时遵循 - 重用已存在的内容,而不是重复,保持代码最小但可维护,并且不留下孤立的代码 - 每个规则都与允许其 **验证** 规则的工具绑定(写入前使用 `already_exists` / `find_symbol`,完成前使用 `dead_code`,重命名前使用 `who_uses`)。它们通过 MCP 自动加载;运行 `sens rules` 以读取它们,或运行 `sens rules --write` 以生成一个可以从您的 `CLAUDE.md` / `AGENTS.md` 中引用的 `SENS_RULES.md`。
## 斜杠命令
Sens 还注册了提示,因此它出现在 Claude Code 的 `/` 菜单中:
| 命令 | 功能 |
| --- | --- |
| `/sens map` | 紧凑的项目地图 |
| `/sens dead-code` | 列出死代码候选项 |
| `/sens find <name>` | 定位符号 |
| `/sens exists <keywords>` | 在编写前检查现有代码 |
| `/sens rules` | 加载工作规则并遵循它们 |
| `/sens dashboard` | 打开网页仪表盘(图表) |
## CLI
您还可以自己驱动 Sens:
```bash
npx sens-mcp index # 构建/更新索引(按文件修改时间缓存)
npx sens-mcp map [subdir] # 紧凑的项目地图
npx sens-mcp find <name> # 符号的定义位置
npx sens-mcp who <name> # 符号被使用的位置
npx sens-mcp outline <file> # 文件的签名,不包含主体
npx sens-mcp exists <kw...> # 是否已存在类似内容?
npx sens-mcp dead-code # 未使用的符号(候选)
npx sens-mcp deps <file> # 文件导入的内容和导入它的内容
npx sens-mcp report # 自包含的 HTML 报告 → .sens/report.html
npx sens-mcp dashboard # 交互式网页仪表盘
npx sens-mcp rules # 打印编码规则(--write 保存为 SENS_RULES.md)
npx sens-mcp usage # 模型实际调用的 Sens 工具
```
> 全局安装(`npm i -g sens-mcp`)后,命令为 `sens <command>`。
## 仪表盘
`sens dashboard` 启动一个本地网页界面(默认 `http://localhost:4319`):
- 项目的 **交互式图表** - 文件作为节点,导入作为边(拖动,单击节点查看其符号);
- 实时 **统计数据** 和可点击的 **死代码** 列表;
- 符号 **搜索**;
- 一键 **连接到 Claude Code** (写入 `.mcp.json`)和 **重建索引** 按钮。
```bash
npx sens-mcp dashboard --root . --port 4319 # --no-open 跳过打开浏览器
```
<p align="center"><i>节点是文件;蓝色 = 有导出,灰色 = 内部,红色 = 有死代码。</i></p>
## 它真的有帮助吗?
一个可复制的基准测试套件([`bench/run.ts`](bench/run.ts))在 Sens 自己的仓库和fixtures上测量这些 - 使用 `npm run bench` 自己运行它。没有估计,没有轶事:下面的每个数字都直接来自该脚本。
| 指标 | 结果 | 如何衡量 |
| --- | --- | --- |
| 项目 **定位** 的大小 | **~97% 更少的字符** | `project_map` 输出 vs. 连接 `src/` 中的每个文件 |
| **重新索引** 时无变化 | **~100-125 倍更快** (因运行/硬件而异) | 中位冷构建(`force: true`)vs. 中位缓存读取,5 次运行 |
| **重复** | 在写入前捕获 | `already_exists("subtract two numbers")` 暴露现有的 `subtract` |
| **死代码** 假阳性 | **8 个标记符号中 0 个** | 与已知使用 / 死 / 对象简写引用的符号的fixtures相比 |
> 在您自己的机器或项目上重新运行 `npm run bench` 以复制(或挑战)这些数字。重新索引速度因 CPU 和磁盘而异,因此将其视为一个范围,而不是一个固定的乘数。
## 工作原理
一个语言无关的索引背后有可插拔的每种语言解析器。Sens 遍历您的源代码(尊重 `.gitignore`),提取具有紧凑签名的顶级符号,解析引用,并将结果缓存到 `.sens/index.json` - 仅在文件修改时间更改时重新构建;模式版本使跨升级的缓存无效。
**语言:**
- **JavaScript / TypeScript** (`.ts .tsx .js .jsx .mts .cts`)通过 [ts-morph](https://ts-morph.com) - 跨文件引用在语义上解析(它遵循您的导入)。
- **Python, Go, Rust, Java, C#, C, C++, PHP, Ruby, Kotlin** 通过 [tree-sitter](https://tree-sitter.github.io/) - 函数,类/结构体,方法,常量和每个文件的导入图。
所有内容都放入一个语言无关的索引中,因此混合仓库(例如 TS 前端 + Python 或 Go 后端)被索引为一个项目。对于 tree-sitter 语言,跨文件引用按名称解析 - 语法解析器在没有整个程序类型推理的情况下能做的最好的事情 - 因此 `who_uses` / `dead-code` 比 JS/TS 更近似:它们高估而不是遗漏,这使得死代码候选项保持保守。添加语言是一个小的独立解析器(`src/indexer/languages/`);更多语言在路线图中。
## 配置
可选的 `sens.config.json` 在您的项目根目录:
```json
{
"ignore": ["**/generated/**"],
"entryPoints": ["src/public-api.ts"]
}
```
- **`ignore`** - 额外的 glob 跳过(在 `.gitignore` ,`node_modules` ,`dist` 之上)。
- **`entryPoints`** - 其导出是您的公共 API 的文件,因此它们永远不会被标记为死。`**/index.*` 文件默认被视为入口点。
## 死代码 - 请阅读此内容
死代码结果是 **候选**,而不是确定性。Sens 无法看到:
- 动态使用(基于字符串的访问,反射);
- 框架 "魔法"(例如 Vue/Nuxt 自动导入的组件 - SFC 支持在路线图中);
- 公共 API 旨在为外部消费者提供(使用 `entryPoints`)。
测试文件被视为使用来源,但它们本身从未被报告为死。**在删除前请验证。**
## 路线图
- [ ] 强制钩子(当编辑引入死代码或重复时警告/阻止)
- [ ] 语义 `already_exists` (嵌入)+ 近似重复检测
- [ ] 通过 tree-sitter 支持更多语言;Vue/Svelte SFC
- [ ] 仪表盘:符号级图表,实时文件监视
- [x] 可复制的基准测试套件(`npm run bench`)
## 贡献
欢迎提出问题和 PR。本地开发:
```bash
npm install
npm run build # 打包到 dist/
npm test # vitest
npm run typecheck
```
`npm link` 使得 `sens` 成为指向您本地构建的全局命令。
## 许可证
[MIT](LICENSE) - 您可以任意使用,只需保留版权声明。查看下面的注释。