你让 Claude Code 跑一个 refactor,半小时后回来发现 npm run build 红了一片:Cannot find name 'XYZ'、Module has no exported member 'foo'、vite.config.ts:12 Unexpected token。Agent 自信地说”已修复并通过测试”,但 build 不会撒谎。这种”AI 一通改完 build 烂掉”是当下最高频的事故之一,原因多数是它动了不该动的 config 文件、加了不存在的 import、或留了开发期的 mock。这篇给你一套定向 revert 的流程:不用全 reset,10 分钟内能精确找到是哪一处改动炸了 build。
常见原因
按命中率从高到低排序。
1. Agent 改了配置文件(tsconfig / vite.config / next.config)
最常见也最痛。Agent 看到一个类型错就去松 tsconfig.json 的 strict,或者把 vite.config.ts 的 resolve.alias 重写一遍——结果一处类型错变成全局 build 失败。
error TS5023: Unknown compiler option 'allowImportingTsExtensions'.
error during build:
RollupError: "default" is not exported by "src/utils/helpers"
如何判断:git diff main -- '*.config.*' tsconfig*.json 看所有 config 文件是否被动过。
2. 加了不存在的 import
Agent 自己虚构了一个 utility 路径(@/utils/superhelper、./lib/notFound),TypeScript 编译过不去:
src/components/Form.tsx:5:18 - error TS2307: Cannot find module
'@/utils/superhelper' or its corresponding type declarations.
如何判断:tsc --noEmit 把所有 TS2307 / TS2305 列出来。
3. 残留了 agent 测试期间的 mock
Agent 在调试时塞了 vi.mock('next/router') 或在 next.config.js 里加了 experimental: { mock: true },提交时忘了移除。
Error: <Link> requires an href prop
如何判断:在 diff 里搜 mock、stub、fixture、TODO、XXX 关键字。
4. 删了被其他文件用到的 export
Agent 觉得某个函数没用,删了它。结果其他 5 个文件还在 import:
src/pages/index.tsx:8:10 - error TS2305: Module './lib/auth'
has no exported member 'verifyToken'.
如何判断:build 失败信息里有 has no exported member 或 cannot find name。
5. 包版本不兼容(API breaking)
Agent 升级了某个包的主版本(比如 React 18 → 19、Next.js 14 → 15),但代码里还在用旧 API:
TypeError: ReactDOM.render is not a function
如何判断:git diff main -- package.json 看是否有主版本跳跃。
6. ESM / CJS 混用
Agent 在 ESM 项目里写了 require(),或在 CJS 项目里写了顶层 import:
SyntaxError: Cannot use import statement outside a module
如何判断:看 package.json 里 "type": "module" 是否设置,对照 import / require 语法。
最短修复路径
按收益排序。Step 1-3 通常能定位 90% 的问题。
Step 1:先 stash,留干净环境对照
不要直接动代码。先存档:
git stash push -m "ai-broken-build-snapshot" # 存档当前状态
git stash apply # 重新应用,不删 stash
这样你随时可以 git stash pop 回到 AI 改完的样子。如果改动已经 commit 了:
git tag broken-build-snapshot # 给当前 commit 打个 tag
Step 2:用 git diff 列出所有改过的文件,按风险排序
git diff main --stat
按这个顺序排查(风险从高到低):
| 优先级 | 文件类型 | 风险 |
|---|---|---|
| 1 | tsconfig*.json *.config.{js,ts,mjs} | 一处坏全站 |
| 2 | package.json package-lock.json | 依赖不兼容 |
| 3 | src/lib/** src/utils/** | 被多处 import |
| 4 | src/components/** | 影响范围有限 |
| 5 | src/pages/** src/app/** | 单页面失败 |
Step 3:跑 tsc --noEmit 暴露所有类型错
不要直接 npm run build,build 会在第一个错就停。先:
npx tsc --noEmit | head -50
这一次性把所有类型错列出来,能立刻看出是”一处改动引发的连锁错”还是”多处独立错”。如果都集中在某一个文件相关的 import 上,定位完成。
Step 4:定向 revert 高风险文件
先 revert 配置文件试试 build:
git checkout main -- tsconfig.json vite.config.ts next.config.js
npm run build
如果 build 过了,问题在 config;如果还挂,恢复 config 改动(git stash pop 或重新 apply),再 revert 下一组:
git checkout main -- src/lib/ src/utils/
npm run build
这样二分查找比全 reset 快。每 revert 一组就 build 一次。
Step 5:把根因写回 prompt 让 agent 重做
定位到具体哪几个文件 / 哪几行后,不要自己手改,而是回头给 agent 一个明确的 prompt:
你上次的改动让 build 挂了。具体错误:
[贴完整 tsc --noEmit 输出]
请只做这些事:
1. 不要碰 tsconfig.json / vite.config.ts
2. 修复以上所有类型错,每个错对应一个最小改动
3. 改完先跑 tsc --noEmit,全绿后再说"完成"
明确禁止它再动 config,这样它不会重蹈覆辙。
预防建议
- 在 CLAUDE.md / AGENTS.md /
.cursorrules里明确禁止改 config 文件,列出具体路径:tsconfig.json、vite.config.*、next.config.*、astro.config.*、package.json(除装包) - pre-commit hook 跑
tsc --noEmit和npm run build,没过不让 commit - 让 agent 每次完工前必须自己跑
npm run build而不仅仅是npm test - 长 refactor 拆成小 commit,每 commit 都能独立 build
- 配置文件改动单独 review,不和业务代码混在一个 PR
- 用
git worktree让 agent 在隔离分支干活,主分支始终保持可 build