内容
<div align="center">
# 👵🏻
</div>
> 停止您的代理重复发明标准库。
**nonna** 是一个用于编码代理的结构化代码相似性引擎,基于 [Opengrep](https://github.com/opengrep/opengrep) 的 IL 构建。它将每个函数的已解析控制/数据流图哈希成一个特征集,并使用加权 Jaccard 和非对称包含来评分配对。匹配是重命名不变的:变量名、字段名、字面值和具体类型默认情况下被忽略 — 两个函数如果计算方式相同,则匹配。
主要循环是 **reuse-before-write**:代理草拟一个函数,询问 `find_similar`,并学习“这已经存在于 dep X 中 — 调用它代替”,跨工作区、所有传递 cargo deps 和 std。
设计、决策和评估:[DESIGN.md](DESIGN.md)。寻找 v1(带有 WASM 演示的 Python 泄漏检测器)? → [nonna-v1](https://github.com/thebabush/nonna-v1)。
## 🏗️ 构建
[](https://github.com/thebabush/nonna/actions/workflows/ci.yml)
Linux 和 macOS(在 Windows 上使用 WSL — 引擎的构建仅限 Unix)。需要 OCaml 5.3.0 opam 开关和 bash ≥ 5。从存储库根目录:
```sh
git submodule update --init --recursive # vendor/opengrep + its grammars
export PATH=/opt/homebrew/bin:$PATH
eval $(opam env --switch=opengrep-5.3.0 --set-switch)
. vendor/opengrep/libs/ocaml-tree-sitter-core/tree-sitter-config.sh
dune build nonna
```
二进制文件: `_build/default/nonna/cli/main.exe`(别名为 `nonna`)。第一次构建编译了 vendored 引擎(一次性)。 Gotcha 集会:tree-sitter env 脚本是必需的(没有它,C 桩将失败),并且任何嵌入解析器的二进制文件都必须调用 `Parsing_init.init ()`(我们的执行)。
## 🔪 命令行界面
```sh
nonna query <corpus...> -- <draft.rs> # 查找与 draft 中每个函数相似的函数
nonna dupes <dir> [-t 0.5] # 库内克隆对
# 过滤器:--metric max|jaccard, --name SUB, --include/--exclude SUB,..,
# --min-lines/--min-features N, -n LIMIT
nonna features <file> # 调试:每个函数的特征转储
nonna graph <file> --fn NAME [-o DIR] # 每个传播轮的 DOT 源
nonna dump-il <file> [--fn NAME] # 紧凑的 IL CFG
nonna corpus <root> # cargo deps + std 发现/缓存
# 基准测试
nonna mine <paths...> [-o pairs.tsv] # 挖掘真实对(token 级别)
nonna eval <pairs.tsv> [-o scores.tsv] # 成对召回率/FPR
nonna rank <pairs.tsv> <corpus...> # 通过管道的 MRR / recall@k
# 服务器
nonna lsp # stdio LSP(诊断,查找相似)
nonna mcp [root] # stdio MCP(每个会话)
nonna serve [root] [-p 8976] # HTTP MCP + 复制浏览器 UI
# 全局标志:--profile structural|full, --iters N, --with ch1,ch2
```
## 🤖 代理集成(MCP)
```sh
# 每个会话(冷索引每个启动):
claude mcp add nonna -- /path/to/main.exe mcp /path/to/workspace
# 或:所有会话共享一个温暖的守护进程
/path/to/main.exe serve /path/to/workspace &
claude mcp add --transport http nonna http://127.0.0.1:8976/mcp
```
工具:`find_similar`(草拟代码 → 排名现有函数与源代码),`query_similar`(文件 + 行|名称),`diff_functions`(A∩B 评分 + 每侧唯一区域按源代码行 — 对于错误/修复对,A−B ≈ 错误,B−A ≈ 修复),`find_duplicates`(工作区克隆对,无查询函数 — 复制/重构视图,带有阈值/度量/名称/包含-排除-路径/大小过滤器),`status`。服务器的 `instructions` 向代理解释评分语义(jaccard ≈ 1:相同直到重命名;包含 ≈ 1:“它做了你所有的事情,而且更多”)。
语料库根在启动时被索引(首先是工作区,然后是 cargo deps + std from per-`crate@version` 缓存位于 `~/.cache/nonna/sigdb` — 第一个 dep 索引约 1 分钟,温暖加载 < 0.5 秒)。在信任空结果之前,请检查 `status`。
`nonna serve` 还在 `http://127.0.0.1:8976/` 主持 **复制浏览器**:语料库中的所有相似对,带有阈值滑块,名称/文件/最小大小过滤器和键盘导航的并排函数差异 — 既是复制导航器,又是查看引擎如何评分真实代码的方式。
## 🧑💻 编辑器集成(VSCode)
`editor/vscode-nonna/` — 打开/保存时的诊断信息(“`avg` 与 `mean` 相似(util.rs:1)- jaccard 1.00”),问题面板中可展开的相关位置,灯泡操作(函数体差异/打开到侧面),以及“nonna:查找相似函数”的调色板命令。设置:参见其 README;简短版本:`npm install`,在那里创建一个符号链接到 `~/.vscode/extensions/nonna-dev.nonna-0.0.1`,设置 `nonna.serverPath`。
## 🧪 测试和基准测试
```sh
bash tests/run.sh # 核心回归(fixtures)
bash tests/sanity.sh # 16 个 Rust/Python/JS/Go 不变性断言
bash tests/lsp-smoke.sh # LSP 协议会话
bash tests/mcp-smoke.sh # MCP stdio + HTTP 会话(包括差异代数)
bash tests/mine-registry.sh # 挖掘并评估针对本地 cargo 注册表的基准
bash tests/sweep.sh bench-out/paths.txt # 超参数扫描(MRR/recall@k)
uv run tests/llm_judge.py --pairs ... --scores ... # LLM 评判的对质量
```
当前头部数字(通过完整管道的排名 MRR;默认按语言调整,需要时不带标志):
| 基准测试 | ALL | 精确 | 重命名 | 进化 MRR / r@5 |
|------------------------------------|-------|-------|---------|-------------------|
| Rust(crates,56k 单位) | 0.963 | 1.000 | 0.987 | 0.766 / 0.859 |
| Python(PyPI,17k 单位) | 0.970 | 1.000 | 0.986 | 0.950 / 0.986 |
| C(Linux v6.10↔v6.16,103k 单位) | 0.918 | 1.000 | 1.000 | 0.888 / 0.944 |
“进化” = 相同的函数在两个真实版本之间编辑 — 很难。完整的表格,每个语言的配置和注意事项都在 DESIGN.md 中。
## 📜 许可证
nonna 的代码是 [MIT](LICENSE)。 vendored 引擎(`vendor/opengrep`,git 子模块 — 不通过此存储库分发)是 LGPL-2.1;从此存储库构建的二进制文件静态链接它,并且 LGPL §6 通过此存储库的公共源代码和构建指令得到满足(您可以重新链接到修改后的引擎)。注意:一些引擎源代码头文件提到了链接异常,但该引擎的 LICENSE 文件实际上并不包含 — 我们保守地假设普通的 LGPL-2.1。
## 🍝 免责声明
充满爱意地编码。