Newshot
Account

Loose Ends:检查 AI 写下的或忘记删除的无用代码

Translation(model translation, not the source's own text)

Loose Ends

npm
npm

为 AI 编写的代码提供由图驱动的活性检查。

每一次变更都应该通向某处。

编码智能体写代码很快,并且会留下一些东西:一个从未被调用的辅助函数,一个紧挨着它所替换的 UserService 的 UserServiceV2

check 在通过时以 0 退出,在有阻断性发现时以 1 退出,在无法运行时以 2 退出。

发现

类型严重性含义
orphaned-additionerror新增的代码,没有任何生产根能到达。
newly-orphanederror在变更前是活跃的,变更后不再活跃的代码。
supersedederror已被替换但未删除的实现。
invalid-suppressionerror没有理由、已过期或匹配不到任何内容的抑制或休眠标记。
test-only-additionwarning新增的代码,只有测试能到达。
newly-test-onlywarning生产环境已不再使用此代码,只有测试仍在使用。
duplicatewarning新增的代码与现有的活跃实现几乎相同。
unused-dependencywarning没有任何活跃代码导入的依赖。
uncertaininfo可达性取决于依赖图无法解析的动态导入。

scan 报告的是现有代码而不是变更,因此它使用 orphaned(没有任何内容到达它)和 test-only(只有测试到达它),外加 unused-dependency 和 uncertain。除非传入 --fail,否则它以 0 退出。

参见 docs/findings.md,了解每种类型的含义以及如何处理。

配置

每个选项都是可选的。npx loose-ends init 会写入一个起始的 loose-ends.config.json:


        {
  "$schema": "https://raw.githubusercontent.com/sid732/loose-ends/main/schema/config.schema.json",
  "entries": ["src/jobs/*.ts", "src/events/handlers.ts#onInvoicePaid"],
  "extendExclude": ["src/generated/**"],
  "languages": ["javascript", "python"],
  "failOn": ["orphaned-addition", "newly-orphaned", "superseded", "invalid-suppression"],
  "checks": ["npm run typecheck", "npm test"]
}
      
  • entries 添加依赖图看不到的根,例如作业运行器按名称加载的文件。
  • extendExclude 添加到默认排除项(node_modules、构建输出、virtualenvs 等)。
  • languages 将分析限制为 javascript、python 和 java 中的一部分。
  • failOn 选择会使 check 失败的发现类型。
  • checks 是 fix --verify 运行的命令。

所有选项、休眠规则和抑制项都在 docs/configuration.md 中。

有意未使用的代码


        // loose-ends: dormant v1 webhooks still arrive until the March cutover
export function handleV1Webhook() {}
      

        # loose-ends: dormant v1 webhooks still arrive until the March cutover
def handle_v1_webhook(): ...
      

Java 像 TypeScript 一样使用 //。loose-ends-file: 注释作用于整个文件,而不是它下面的声明。

休眠标记和抑制项需要理由。没有理由时,它们自身就会成为发现。参见 docs/configuration.md。

在 CI 和拉取请求中


        # .github/workflows/loose-ends.yml
name: Loose Ends
on: pull_request
permissions:
  contents: read
  pull-requests: write # for the PR comment
jobs:
  liveness:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0 # the base commit must exist locally
      - uses: sid732/loose-ends@v1
      
  • GitHub Action(无需服务器,在公共仓库上免费):在 diff 上添加内联注释,保持一条 PR 评论是最新的,将报告写入作业摘要,并在有阻断性发现时使作业失败。它也适用于 Python 和 Java 仓库,无需 Node 设置步骤。
  • GitHub App:以 check runs 形式提供相同的报告,适合更愿意托管服务器并在多个仓库中一次性安装的人。

输入项(working-directory、fail-on、comment、sarif 等)和 App 设置都在 docs/github.md 中。

面向编码代理

  • MCP server:npx -y @loose-ends/mcp 暴露 check_changes、scan_project、explain、list_roots 和 plan_cleanup。它们全部都是只读的。
  • Skills:skills/ 中有两个简短的 SKILL.md 文件,告诉代理何时运行 check 以及如何响应每种发现。

        { "mcpServers": { "loose-ends": { "command": "npx", "args": ["-y", "@loose-ends/mcp"] } } }
      

清理


        npx loose-ends fix --verify --patch cleanup.diff
      

fix 会把阻断性发现转换为文件删除和声明移除,并将它们应用到项目的临时副本。然后它在那里运行你配置的检查(npm test、npm run build、…)并写入一个补丁。任何会导致悬空导入的内容都会被跳过,并列出原因。--apply 会把更改写入你的工作树,并且只在验证通过后才会写入。

覆盖率作为证据


        npx loose-ends check --coverage coverage/coverage-final.json
      

来自 istanbul 或 lcov 报告的运行时命中次数会附加到发现项上。覆盖率绝不会取代依赖图。它用于解释依赖图:依赖图认为不可达但仍然运行过的代码,指向依赖图看不到的加载器。

范围

  • TypeScript 和 JavaScript:Node.js、React、Next.js、Vite、Express、NestJS、React Router framework mode、Vue、Svelte 和 SvelteKit、Astro、Nuxt、VitePress、npm/yarn/pnpm workspaces、浏览器扩展,以及常见测试运行器。
  • Python:包和 src 布局、相对导入和命名空间导入、__init__.py 重新导出和 __all__、脚本、notebook、pyproject/setup.py 入口点、Django、Flask、FastAPI、Celery、Alembic、Airflow、Streamlit、pytest,以及 requirements*.txt、pyproject.toml、setup.py、setup.cfg 和 Pipfile 中的依赖。
  • Java:顶层类、接口、枚举和 record;导入、同包引用和全限定引用;main 方法;Spring、Jakarta EE、CDI、JAX-RS、Quarkus、Micronaut、MyBatis、MapStruct、Dagger/Hilt 和 Android;资源文件中的类名;Maven 和 Gradle(包括版本目录)依赖;以及从 Kotlin 使用的 Java 代码。

一个仓库可以混合使用所有这些。其工作方式在 docs/architecture.md 中描述。

限制

  • 跟踪止于顶层声明。已使用类中的未使用方法,或已使用对象上的未使用属性,不会被报告。
  • 仅通过按名称依赖注入、基于字符串的插件注册表或反射到达的代码,对依赖图不可见。将其添加到 entries,或用 loose-ends: entry 标记。
  • 带有框架注解(@Service、@Controller、@Entity、…)的 Java 类会被视为入口点,因此永远不会被报告为未使用。
  • Kotlin 和 Groovy 只会扫描它们使用的 Java 名称。它们自身的代码不会被分析。
  • 使用计算名称的 Python getattr,以及通过 sys.path 变更找到的模块,不会被跟踪。
  • 其他语言不会被分析。

贡献

设置、拉取请求规则和发布流程见 CONTRIBUTING.md。要报告漏洞,请参阅 SECURITY.md。

许可证

The translation is machine-generated and individual terms may be off. Nothing is rewritten or cut; the original is authoritative.

Published by HN AI
This site only summarises and aggregates; copyright stays with the original author. Headlines and summaries follow the source — where they differ, the original wins.
Read the original ↗