
Loose Ends 推出代码存活检查工具,检测 AI 编写或遗留的未使用代码
来源标题:Loose Ends: A check for unused code AI wrote or forgot to remove
Loose Ends 以图结构为基础做存活分析,在合并前检查 AI 编码代理新增或改动过的代码是否仍能从真实入口访问。它会报告未被引用的新文件、被替换但未删除的旧服务(如 UserService 与 UserServiceV2 结构相似度达 100%)以及已注销路由遗留的处理函数,并给出证据链。可通过 npx loose-ends check 运行。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
有人以为留着这些代码“以后可能用得上”,结果它们一直躺在仓库里吃灰。这个工具就是用来清理这类残留代码的。以下为译文:
基于图的活性检查,专治 AI 写代码时留下的残留。
编程 Agent 写代码很快,但也会留下不少东西:一个从未被调用的 helper、一个和它替换掉的 UserService 并排放着的 UserServiceV2、一个路由被注销了但 handler 还留着。Loose Ends 在合并前检查每一处改动,并给出证据,报告它新增或触及的代码是否仍能从真实入口点到达。
$ npx loose-ends check
Loose Ends · check main (dc9af08) → working tree
4 files changed
✖ error orphaned-addition src/lib/pagination.ts:1
File added in this change is not reachable from any entry point.
Import it from live code, add it to entries, or mark it with // loose-ends-file: dormant <reason>.
✖ error superseded src/services/users.ts:1
src/services/users.ts appears to have been replaced by src/services/users-v2.ts#listUsersV2 but was not removed: its callers now use the new code (src/routes/users.ts); the names match; 100% structural similarity. Delete it, or mark it dormant with a reason.
edge removed: src/routes/users.ts → src/services/users.ts
was reached via: src/server.ts → src/routes/index.ts → src/routes/users.ts → src/services/users.ts
root: entry point "src/server.ts" of express-api-example
related: src/services/users-v2.ts#listUsersV2
Summary: 2 errors, 0 warnings, 0 info
Files: 6 live, 0 test-only, 2 orphaned, 0 uncertain, 0 dormant
Result: fail (2 findings in failOn: orphaned-addition, superseded)
这就是 express-api 示例在一次 Agent 风格改动之后的样子:新增了一个 v2 服务并接入,原服务被丢在一旁,同时还加了一个没人用的分页 helper。
新增的代码必须能从公认的产品入口点到达。
改动不得通过移除保持原有代码存活的边,让既有代码变成孤儿。
被替换的实现必须删除,或者给出明确理由。
Loose Ends 会为 TypeScript、JavaScript、Python 和 Java 代码构建一张 Liveness Graph:imports、exports、re-exports、顶层声明之间的引用、动态 import,以及包依赖。它从包清单、脚本、框架约定(Next.js 路由、Vite 入口、浏览器扩展 manifest、serverless functions、工具配置、Django apps、pyproject entry points、Dockerfile 和 Procfile 中的服务命令、Spring 与 Jakarta 注解、Android manifest 和 layout)、配置以及测试中寻找根节点。它分析 base 和 head 两个版本,只报告这次改动造成的影响。既有的死代码永远不会阻塞 pull request。
它不是让 LLM 去猜代码看起来是否没人用,也不是通用代码审查器、格式化工具或安全扫描器。它不会声称未被观测到的代码就可以安全删除,也绝不在缺少确定性证据和通过的验证运行的情况下删除任何东西。
bench/RESULTS.md 里有在公开仓库上的结果,包括约 700 个 Python 和 Java commit 通过 check 重放,以及对 30 个热门仓库的扫描。
npm install --save-dev loose-ends
需要 Node.js 20 或更高版本,以及 git。
Python 和 Java 项目不需要 package.json。装好 Node 后,在仓库根目录运行 npx loose-ends check 即可。
npm 包通过 GitHub Actions 带 provenance 发布,因此每个版本都能链接回它构建时所用的 commit。
npx loose-ends check # working tree vs. 与默认分支的 merge base npx loose-ends check --base origin/main --head HEAD npx loose-ends check --format markdown # 还支持:json、sarif npx loose-ends scan # 全项目报告既有债务 npx loose-ends explain src/lib/format.ts#formatUser npx loose-ends roots # 什么算作入口点,以及为什么 npx loose-ends fix --verify --patch cleanup.diff npx loose-ends init # 生成 loose-ends.config.json 初始模板
check 通过时退出码为 0,有阻塞性发现时为 1,无法运行时为 2。
Kind Severity 含义
orphaned-addition error 新增的代码没有任何生产根节点能到达。
newly-orphaned error 改动前是活的,改动后不再是活的。
superseded error 被替换的实现没有删除。
invalid-suppression error 某个 suppression 或 dormant 标记没有理由、已过期,或没有匹配到任何东西。
test-only-addition warning 新增的代码只有测试能到达。
newly-test-only warning 生产代码不再使用这段代码,只有测试还在用。
duplicate warning 新增的代码与某个既有的活跃实现几乎完全相同。
unused-dependency warning 没有任何活跃代码 import 的依赖。
uncertain info 可达性取决于图无法解析的动态 import。
scan 报告的是既有代码而非某次改动,因此它使用 orphaned(没有任何东西能到达)和 test-only(只有测试能到达),外加 unused-dependency 和 uncertain。除非传入 --fail,否则它以 0 退出。
每种 kind 的含义以及该怎么处理,见 docs/findings.md。
所有选项都是可选的。npx loose-ends init 会写出一个 loose-ends.config.json 初始模板:
"$schema": "https://raw.githubusercontent.com/sid732/loose-ends/main/schema/config.schema.json
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。