Composer 应用完编辑,碰过的文件里没有红波浪线,你跑 pnpm build 立刻挂:missing import、type 错位、Prisma client 没更新、ESM/CJS 不匹配。原因很机械,不神秘:Cursor 的 Apply 只校验它改的那一个文件局部正确,不跑全图 typecheck,不跑你的 codegen step,更不知道你的 CI 容器长什么样。于是出现”局部绿、全局红”。
最快的修法(先做这个): 让 agent 在汇报”完成”之前自己 build 一遍。在 Cursor 里打开 Settings → Agent → Auto-run(这是当前版本 Cursor 把 “Yolo mode” 改的名,截至 2026 年 6 月仍是这个叫法),用自然语言写一条 allow-list,比如”允许跑 pnpm typecheck、pnpm build、pnpm test、eslint”。然后给 Composer 一条规则:“After any code change, run pnpm build; if it fails, fix it and run again; only stop when it is green.”(改完代码就跑 build,失败就修了再跑,绿了才停。)下面这些故障大多会因此消失,因为 agent 现在看到的错误跟你一样,并会自己迭代。
下面这部分是当仍有一条错误漏网时的对症诊断。
你属于哪一类?
把 build 错误的第一行对照下表,再跳到对应修法。
| build 错误里出现 | 大概率原因 | 跳到 |
|---|---|---|
Expected N arguments, but got M | 改了签名,没改全调用点 | 原因 1 / Step 2 |
Cannot find module / Module not found | 新文件、import 路径或 alias 不对 | 原因 2 / Step 3 |
路径指向 .prisma/、src/generated/、__generated__/ | codegen 没重跑 | 原因 3 / Step 4 |
ERR_REQUIRE_ESM / Cannot use import statement outside a module / X is not a function | ESM/CJS 不匹配 | 原因 4 / Step 5 |
| 一个 env 变量名或 fixture 文件路径;本地过、CI 挂 | 代码读了 CI 没有的 env / 文件 | 原因 5 / Step 6 |
本地用 tsc --noEmit 复现不出来的 type 错 | build 用了更严的 tsconfig | 原因 6 / Step 6 |
常见原因
1. 改了函数签名漏了调用点
Cursor 把 foo(a, b) 改成 foo(a, b, c),但只改了它当时打开的 3 个调用点,仓库里其它 7 个报 Expected 3 arguments, but got 2。
如何判断:跑 pnpm typecheck 再用 grep "Expected" 过滤,错都集中在某一个函数 / type 上。
2. 新建文件没加 import 或路径不对
Composer 创建了 src/utils/parseInvoice.ts,但调用方写的是 from "./utils/parse-invoice"(kebab-case)或 from "@/utils/parseInvoice"(依赖一个可能根本没配的 path alias)。本地 dev server 宽容,build 严格。
如何判断:构建错误里出现 Cannot find module 或 Module not found。
3. Codegen 没重跑
改了 Prisma / GraphQL / protobuf / OpenAPI schema 后,对应生成的 client 或 types 没重新生成。代码引用的新字段在生成产物里还不存在。
如何判断:错误指向 node_modules/.prisma/、src/generated/、__generated__/ 这类生成目录。
4. ESM / CJS 不匹配
Composer 在一个 CommonJS 项目里写了 import { foo } from "esm-only-package",或者在纯 ESM 项目里用了 require()。dev 运行器(ts-node / tsx)能容忍混用,打包器(esbuild / Vite / Rollup)会爆。
如何判断:错误带 ERR_REQUIRE_ESM、Cannot use import statement outside a module、或 X is not a function。
5. 引用了 CI 没有的 env / 文件
新代码读 process.env.NEW_TOKEN 或某个本地 fixture 文件。本地有,CI 容器里两样都没有,build 时报 undefined 或 ENOENT。
如何判断:构建错里出现一个 env 变量名或文件路径;本地能 build,CI 挂。
6. tsconfig 多份(dev vs build)
tsconfig.json 宽松(noEmit、skipLibCheck),tsconfig.build.json 严格(strict、noUnusedLocals)。Cursor 和你的编辑器按宽松那份检查,build 走严格那份。
如何判断:跑 ls tsconfig*.json;如果有多份,比较它们的 strict 设置。
动手前先确认
- 确认 build 失败是在本地、CI、还是 production deploy。只在一处挂提示你查 env / 配置差异(对应原因 5 和 6)。
- 复现前先 commit 一次,这样能准确判断是哪次改动挂了,也方便干净回滚。
- 记下 Cursor 版本和当前模型(Composer 2.5、Sonnet 4.6、GPT-5.5 等)。不同模型 import 路径风格不同——有的偏好相对路径,有的偏好 path alias。
需要收集的信息
- 完整 build 错误日志——留第一行和最后一行,中间通常是级联噪音。
- Composer 最近一次 turn 的 prompt 加它的 diff stat。
tsconfig.json/tsconfig.build.json,以及package.json里的buildscript。- 是否有 codegen step,上次成功跑是什么时候。
- 本地 Node / pnpm 版本 vs CI 用的版本。
最短修复路径
按”先全图扫一遍,再按错类型对症”。
Step 1:跑完整 typecheck + build
pnpm typecheck # 或 tsc --noEmit
pnpm build
读第一条错误,不是最后一条。AI 引入的错通常级联,第一条最接近 root cause。
Step 2:签名改动让 Composer 自己扫调用点
I changed the signature of `foo` from (a, b) to (a, b, c).
List EVERY call site in the repo and update each one.
After updating, run `pnpm typecheck` and paste the result.
让 agent 自己跑 typecheck 验证,别只信它自己扫的结果。
Step 3:missing import 让模型修正路径
Build fails with "Cannot find module './utils/parse-invoice'".
The file is actually at src/utils/parseInvoice.ts (camelCase).
Update all import paths to match. Verify with tsc --noEmit.
Step 4:codegen 漂了重跑
pnpm prisma generate
pnpm codegen # GraphQL
pnpm proto # protobuf
把 codegen 做成常驻规则。在 Cursor 里现在的正确做法是用 project rule 文件,而不是老的 .cursorrules(它还能用,但已在逐步淘汰,见 FAQ)。新建 .cursor/rules/codegen.mdc,frontmatter 写 alwaysApply: true,正文:
After any change to a *.prisma, *.graphql, or *.proto file, run the
matching codegen command (e.g. `pnpm prisma generate`) before declaring
the task done.
Step 5:ESM/CJS 按项目实际类型修
看 package.json 的 "type" 字段。"type": "module" 全用 import;缺这个字段或 "type": "commonjs" 全用 require。让 Composer 把这个文件改得跟项目其余部分一致,并记住 ESM 的相对 import 要显式带 .js 扩展(from "./foo.js",不是 from "./foo")。
Step 6:只在 build / CI 挂的查 env + tsconfig
diff tsconfig.json tsconfig.build.json
grep -A 3 "env" .github/workflows/*.yml
把严格那份 config 喂给 Composer:
We use tsconfig.build.json (strict mode) for production. Re-check your
changes under that config and fix any new errors. Run:
tsc -p tsconfig.build.json --noEmit
env 缺失的话,确认这个变量在 CI secrets 和 .env.example 里都声明了,而不是只在你本地的 .env。
怎么确认已经修好
- 本地
pnpm typecheck && pnpm build都过。 - push 后 CI 全绿——build 和整套测试都过,不只是 unit test 绿。
- 在干净 checkout 上
pnpm install && pnpm build能跑通。这能抓出 env 漂移和悄悄变动的 lockfile。 - 往后只要开着 Auto-run,Composer 的最后一条消息应该明确说它跑过 build 并通过了。
如果还是没修好
- 把错缩到最小:单个 import,或单条 type 报错。
- 回滚 Composer 那条 commit,确认 build 是否恢复,再逐 hunk 重新 apply,找出闯祸的那块。
- 在 forum.cursor.com 搜对应错误文案;附上
tsconfig、package.json和日志。 - 通过 Help → Report Issue 导出日志(可以附诊断日志),或抓 agent 输出贴到 Bug Reports 板块。
预防建议
- CI 强制:每个 PR 跑完整 typecheck + build + 整套测试,不只 unit。
- 打开 Settings → Agent → Auto-run,给
typecheck、build、lint、test配 allow-list,让 Composer 自我验证。把破坏性命令(rm -rf、git push --force)排除在 allow-list 之外。 - 加一条 project rule:
.cursor/rules/verify.mdc,写alwaysApply: true,正文 “After any code change, runpnpm buildand report errors before finishing.”(你也可以在仓库根放一个纯 markdown 的AGENTS.md。) - pre-commit hook:至少对 staged files 和它们的引用方跑
tsc --noEmit。 - Schema 项目(Prisma / GraphQL / Protobuf)把”改 schema 必须接 codegen”写成铁规则。
- 让 Composer 任务以 “I ran the build and it succeeded” 收尾,不是 “I’m done”。
常见问题
为什么 Cursor 说改动是干净的,build 却明显不干净?
Apply 只在编辑器的宽松上下文里对它改的那一个文件 typecheck,不跑项目级 tsc、不跑 codegen、不跑打包器,也从来看不到你的 CI 配置。修法是让 agent 真的跑一遍 build(Auto-run),这样它对”完成”的判断才和你一致。
该用 .cursorrules 还是 .cursor/rules/*.mdc?
优先用 .cursor/rules/*.mdc。截至 2026 年 6 月,单文件的 .cursorrules 还能加载,但已被当作 legacy 并在逐步淘汰。.cursor/rules 目录里放受版本控制的 .mdc 文件,有四种应用模式——Always、Apply Intelligently、Apply to Specific Files(按 glob)、Manual(@rule-name)。build 验证类规则用 alwaysApply: true。仓库根放一个 AGENTS.md 是更简单的纯 markdown 替代方案,Cursor 同样会读。
Auto-run 是什么?安全吗? Auto-run(前身是 “Yolo mode”)让 agent 不必逐条确认就能跑终端命令,由你写的自然语言 allow-list 把关。对 build、test、lint、codegen 这类命令是安全的。破坏性或贴近生产的命令别开,commit 前先看 diff。
build 只在 CI 挂,本地从不挂,为什么?
你几乎可以确定是原因 5 或 6:更严的 tsconfig.build.json、缺失的 env 变量 / secret、缺失的 fixture 文件,或 Node/pnpm 版本差异。本地用 tsc -p tsconfig.build.json --noEmit 加干净的 pnpm install 复现 CI,并检查每个新 env 变量在 .env.example 和 CI secrets 里都有。
Composer 把每条错都”修”了,但新错不断冒出来,怎么办?
这是在追级联错。别再逐行打补丁了。回滚到上一个绿的 commit,把改动作为一个整体重新 apply,让 Auto-run 驱动 pnpm build 跑到底,这样 agent 是一次性修根因,而不是治标。