内容
# Necro
**通过证据而非猜测发现无效代码。** Necro 是一个本地、免费、多语言的 CLI 工具,用于发现反模式代码并提出 LLM 辅助修复 - 并且拒绝在纯静态工具无法确定时进行猜测。
> **状态:v1.2 — 在 [npm](https://www.npmjs.com/package/@manehorizons/necro) 上发布。**
> Necro 分析 **TypeScript** 的多个方面 - 无效代码(带有置信度等级、证据链和 `仅测试` 判决)、复杂性、风险热点和重复代码 - 以及安全的无效代码删除(`fix`)、LLM 对模糊发现的分类(`triage`)、LLM 辅助重构(`refactor`)和用于 AI 代理的只读 [MCP 服务器](#从AI代理使用MCP)(`mcp`)、**SARIF 输出 + `--fail-on` 门控 + GitHub Action** 用于持续集成。更多框架插件和 Python 支持在 [路线图](#路线图) 中。
## 为什么选择 Necro
每个分析轴都有强大的竞争对手,但没有免费、本地的工具能够将它们与跨语言的修复推理结合起来。Necro 填补了这一空白:
**免费 + 本地 + 多轴 + LLM 辅助修复 + 多语言。**
无效代码意味着“无法从任何入口点访问”。纯静态工具必须进行二进制的生/死调用,并在不确定时承担假阳性。Necro 的优势在于**拒绝猜测**:
- **置信度等级** - `确定` / `可能` / `可能不`。模糊代码被隔离在 `可能不` 中,而不是被错误地删除。
- **证据链** - 每个发现都附带其推理(静态引用、包导出、动态导入污染),以便您审核判决。
- **`仅测试` 判决** - 生产无效代码仅由测试保持活跃,这是一个信号,表明没有竞争对手能够 cleanly 地显示出来。
- **语义而非文本** - 无效代码检测基于 TypeScript 编译器 API(通过 [ts-morph](https://ts-morph.com)),遵循重新导出、类型导入和 barrel 文件。
## 安装
需要 **Node.js ≥ 20**。
从 npm 全局安装:
```bash
npm install -g @manehorizons/necro
necro scan src/
```
或在无需安装的情况下运行(适用于代理和持续集成):
```bash
npx -y @manehorizons/necro scan src/
```
<details>
<summary>从源代码安装</summary>
```bash
git clone https://github.com/manehorizons/necro
cd necro
npm install
npm run build # 将 CLI 捆绑到 dist/cli.js
node dist/cli.js scan src/
```
</details>
## 快速入门
将 `necro scan` 指向一个目录(默认为 `.`):
```bash
necro scan src/
```
您将获得一行摘要,然后是每个发现的 **证据链**,按严重程度排序:
```
3 findings (1 certain, 1 likely, 1 test-only)
deadFn src/util.ts:2 tier: certain
✓ 0 static references (TS compiler)
• coverage: not available
✓ not in package.json exports
✓ no dynamic-import taint in scope
→ safe to remove
lonelyExport src/util.ts:3 tier: likely
✓ 0 static references (TS compiler)
• coverage: not available
✓ not in package.json exports
✓ no dynamic-import taint in scope
→ exported but unused — confirm no external use, then remove
testUtil src/util.ts:4 tier: maybe
✓ 0 production references
✗ referenced only in test files
• coverage: not available
→ prod-dead — delete fn + test, or wire into prod
```
- **`deadFn`** 是私有且未被引用的 → `确定`,可以安全删除。
- **`lonelyExport`** 被导出但在内部未被使用 → `可能`(可能被外部使用,因此 Necro 要求您确认)。
- **`testUtil`** 仅通过测试可达 → `仅测试` 判决。
在无效代码发现下面,`scan` 还会打印 **复杂性**(过复杂函数 - 嵌套、循环、认知、神函数)、**风险热点**(CRAP 分数 × git 变更,按严重程度排序)和 **重复**(Type-2 复制粘贴克隆)- 每个部分如果为空,则省略。
### 处理发现结果
```bash
necro fix src/ # 预览删除确定的无效代码(仅差异)
necro fix src/ --write # 应用它(如果 git 工作树脏,则拒绝;--force 覆盖)
necro triage src/ # LLM 解析隔离的 `maybe` 发现(可选,Anthropic API)
necro refactor src/ --type god-function # 提出 LLM 重构,在临时工作树中验证
necro refactor src/ --type extract-duplicate # 从克隆中提取共享函数
```
`triage` 和 `refactor` 是可选的,并调用 Anthropic API(设置 `ANTHROPIC_API_KEY`);`scan` 和 `fix` 是完全本地和免费的。`refactor` 打印提案 - 它永远不会编辑您的文件 - 并且每个提案都在一个临时 git 工作树中验证(类型检查 + 测试)后显示。
#### `fix` 退出代码
`fix` 使用稳定的退出代码分类法,以便脚本和持续集成可以根据输出进行分支,而无需解析输出:
| 退出 | 含义 |
|---|---|
| `0` | 已写入、预览或无需修复 |
| `1` | 意外错误 |
| `2` | 拒绝 - git 工作树有未提交的更改(传递 `--force` 以覆盖) |
| `3` | 拒绝 - 0 个生产入口点已解析(参见下面的 **关闭入口解析失败**) |
如果同时满足这两个条件(脏树 *和* 未播种的可达性),则退出 `3` 胜过 - 您需要修复入口解析,然后才能进行脏树覆盖才有意义。
#### 关闭入口解析失败
Necro 从您的包的生产入口点(`package.json` `main`/`module`/`bin`/`exports`,通过 `tsconfig.json` `outDir`/`rootDir` 映射到源代码,当清单指向构建输出时,`package.json` `scripts` 值,诸如 `src/index.ts` 之类的约定名称,以及工作区成员条目)。如果 **没有** 这些在非空代码库中解析,则可达性未播种 - Necro 无法确定什么是实际无效的 - 因此它会关闭:每个无效代码发现都被降级为 `maybe`(永远不会自动修复 eligible),警告横幅解释了原因,并且 `fix --write` 拒绝退出 `3` 而不是猜测。`necro scan` 始终报告它已解析的内容和来源,在 `diagnostics.entryResolution` 下(也在 `--json` 和 `--sarif` 输出中作为 `runs[0].properties.entryResolution`)。
要解决警告,请执行以下操作之一:
1. 将 `package.json` `main`/`module`/`bin`/`exports` 指向您的真实入口文件(添加 `tsconfig.json` `outDir`/`rootDir`,以便 Necro 可以将 `dist/` 映射回 `src/`)。
2. 在 `necro.config.json` 中添加 `entries` 字段(参见 **配置**)。
3. 使用约定入口文件名(`index.ts`、`src/index.ts`、`main.ts`、`src/main.ts`)。
### 输出模式
```bash
necro scan src/ --json # 机器可读的 JSON(用于持续集成)
necro scan src/ --sarif necro.sarif # SARIF 2.1.0 用于 GitHub 代码扫描
necro scan src/ --fail-on high # 在确定无效代码时退出非零
necro scan src/ --top 10 # 仅显示 10 个最差的发现
necro --version
```
成功的扫描始终退出 `0`,除非 `--fail-on <high|medium|low>` 已设置 - 然后如果存在严重性为或高于该严重性的发现,则退出 `1`。有关 SARIF + GitHub Action 设置,请参见 [持续集成](https://github.com/manehorizons/necro)。
## 从 AI 代理(MCP)使用
Necro 作为只读 [MCP](https://modelcontextprotocol.io) 服务器通过 stdio 运行,因此代理(Claude Code、Cursor、Codex、Windsurf)可以调用 Necro 的基于证据的判决并在隔离环境中验证其自己的编辑 - Necro **从不编辑您的文件,也从不包装 LLM**:
```bash
necro mcp # 通过 stdio 提供服务
```
暴露了四个只读工具:
- **`necro_scan`** - 与 `necro scan --json` 相同的发现(无效代码层级 + 证据链、复杂性、热点、重复)。
- **`necro_verify`** - 在临时 git 工作树中应用一组 `{file, content}` 编辑,运行检查(默认:类型检查 + 测试),并报告 `{ok, output}`。您的 working 树永远不会被触及。
- **`necro_verify_removal`** - 对于每个命名符号,计划其删除并在自己的临时工作树中独立验证;返回一个每符号的判决(绿色/红色/未解析),以便您在应用之前确认删除代码是安全的。
- **`necro_explain`** - 跟踪符号为何存活、仅测试或无效(与 `necro explain --json` 相同的 JSON);设置 `narrate: true` 以获取附加的 LLM 明白英语解释(需要 API 密钥,如果没有则优雅降级)。
用您的代理(Claude Code 示例)注册它:
```bash
claude mcp add necro -- npx -y @manehorizons/necro mcp
```
或手动:
```json
{
"mcpServers": {
"necro": { "command": "npx", "args": ["-y", "@manehorizons/necro", "mcp"] }
}
}
```
## 配置
Necro 零配置运行。要自定义它分析哪些文件,请在项目根目录中添加一个 `necro.config.json`:
```json
{
"include": ["**/*.ts", "**/*.tsx"],
"ignore": ["**/node_modules/**", "**/dist/**"],
"entries": ["src/server.ts"]
}
```
您设置的每个键都 **替换** 其默认值。声明文件(`*.d.ts`)和 `node_modules`、`.git`、`dist`、`build` 和 `coverage` 目录始终被跳过。
`entries` 是 glob(相对于扫描目标),直接声明生产入口点 - 规范的修复失败关闭警告横幅,当 Necro 的自动解析(清单、dist→src 映射、脚本、约定名称、工作区)找不到一个时。匹配的文件作为生产根添加到 `diagnostics.entryResolution` 中的源 `"config"`。
## 工作原理
扫描是一系列小型、独立测试的阶段:
```
发现文件
→ 构建符号图 (ts-morph;唯一语言特定部分)
→ 解析入口 (生产入口 + 框架插件)
→ 双色可达性 (+ 污染) ─┐ 无效代码 → 层级
→ 分类到层级 │
→ 语法检测器 (tree-sitter) ─┤ 复杂性 · 热点 · 重复
→ 评分 (CRAP × 变更) │
→ 渲染(终端 / JSON) ─┘
```
静态分析始终开启、确定且免费。**LLM 层是混合且按需的** - `triage` 和 `refactor` 仅为您询问的发现调用 Anthropic API,因此成本随请求修复而扩展,而不是代码库大小。重构提案在显示之前在临时 git 工作树中验证(类型检查 + 测试),并且 Necro 自身计算差异(模型返回代码,从不补丁)。
**核心不变性**:特定于语言的代码仅存在于符号图适配器中。可达性、分类、评分和报告是与语言无关的 - 因此添加语言(计划支持 Python)意味着编写一个新的适配器,而不是触摸引擎。测试文件从您的真实测试运行器配置(jest `--showConfig` / vitest)中识别,因此测试基础设施永远不会被标记为无效。[MCP 服务器](#从AI代理使用MCP) 使用相同的引擎,它重用了 `scan` 和工作树验证器而无需分叉其逻辑。
参见 [架构文档](#文档) 和 [`docs/necro-design-spec.md`](docs/necro-design-spec.md) 以获取完整设计。
## 文档
完整的文档站点(主页 + 指南 + 参考 + 架构)位于 [`website/`](website/),使用 [Astro Starlight](https://starlight.astro.build) 构建。
在本地运行:
```bash
cd website
nvm use 22 # 文档站点需要 Node ≥ 22(Astro 6)
npm install
npm run dev # → http://localhost:4321/necro/
```
或构建和预览静态站点:
```bash
npm run build # 输出静态 HTML 到 website/dist/(带搜索)
npm run preview
```
> 站点通过 [.github/workflows/docs.yml](.github/workflows/docs.yml) 配置为部署到 GitHub Pages;部署步骤是手动的(`workflow_dispatch`),直到 Pages 在存储库中启用。
## 项目布局
```
src/
├─ cli.ts commander CLI(scan · fix · triage · refactor · mcp)
├─ config.ts necro.config.json 加载器
├─ discover.ts / glob.ts 文件发现
├─ engine/ 扫描管道 + 生产入口解析
├─ graph/ 符号图(ts-morph)- 语言适配器
├─ syntactic/ tree-sitter 检测器:复杂性、重复、指标
├─ plugins/ FrameworkPlugin 合同 + 测试运行器插件
├─ analyze/ 可达性、污染、层级分类、热点、覆盖率
├─ fix/ 安全的确定无效代码删除 + 脏树防护
├─ triage/ LLM 解析 `maybe` 发现(Anthropic)
├─ refactor/ LLM 重构 + 临时工作树验证
├─ mcp/ 只读 MCP 服务器(necro_scan, necro_verify)
└─ report/ 证据链、终端/JSON 输出、排序
test/ vitest 套件,镜像 src/
website/ Astro Starlight 文档站点
docs/necro-design-spec.md 完整设计参考
```
## 开发
需要 **Node.js ≥ 20**(`website/` 下的文档站点需要 Node ≥ 22)。
```bash
npm test # vitest,单次运行
npm run test:watch # vitest 监视模式
npm run typecheck # tsc --noEmit
npm run build # 捆绑 CLI(esbuild)
```
Necro 是 **测试优先**(红 → 绿 → 重构)构建的,并使用 [CADENCE](https://github.com/manehorizons/cadence) 草案 → 构建 → 结算工作流程;阶段性制品位于 `.cadence/`。带有测试和明确验收标准的贡献符合代码库的构建方式。
## 路线图
**今日可用**(TypeScript):
- 语义 **无效代码** 检测(TS 编译器 API via ts-morph),置信度层级,证据链,`仅测试` 判决,测试运行器感知(jest/vitest)和 lcov **覆盖率摄入**。
- **复杂性** 检测器(嵌套、循环、认知、神函数)带有可配置的阈值。
- **风险热点**:CRAP 分数(复杂度² × (1 - 覆盖率)³ + 复杂度)× git 变更,按严重程度排序。
- **重复**:Type-2(重命名)克隆检测,限制在函数边界 - 没有 jscpd。
- **`fix`**: 安全删除 `确定` 无效代码(默认预览,脏树防护)。
- **`triage`**: `maybe` 发现的 LLM 解析(可选,Anthropic API)。
- **`refactor`**: LLM 神函数分割和提取重复,在临时工作树中验证。
- **`explain`**: 跟踪符号为何存活、仅测试或无效,带有可选的 `--narrate` LLM 明白英语层(可选,Anthropic API)。
- **`verify-removal`**: 在临时工作树中按符号进行构建绿色检查 - 在您应用之前确认删除是安全的。
- **`mcp`**: 只读 MCP 服务器(`necro_scan`、`necro_verify`、`necro_verify_removal`、`necro_explain`)用于 AI 代理。
- **框架插件**:Next.js(根 App-Router 出口导出)和 monorepo 工作区边缘解析。
- 输出:终端、`--json`、`--top N`。
**计划中**(尚未实施):
| 领域 | 计划能力 |
|---|---|
| 检测器 | 跨语言和模糊(Type-3)克隆;神函数责任聚类 |
| 评分 | 每行和基于最近的变更加权,归属权重 |
| 修复 | `仅测试` 自动应用;修复后的级联重新分析 |
| 框架 | NestJS(DI),基于模板的插件 |
| 语言 | Python(检测器重用,新符号图适配器) |
## 许可证
[MIT](LICENSE) © manehorizons。