你让 Cursor 修一个 React 组件,它却引用了 dist/components/Foo.js(已编译的旧版)里的 prop 名,导致 patch 完全不对。或者你问”我们怎么实现 rate limit 的?“,它回答的是 vendor/express-rate-limit/ 里的源码,而不是你自己写的中间件。这都是 Cursor 把”不该读的文件”塞进了 context window——构建产物、vendored 第三方库、备份文件、生成代码。这篇给出诊断方法和让 Cursor 只看源码的清理步骤。
常见原因
按出现频率从高到低排序。
1. 生成文件和源码混在一起
dist/、build/、.next/、coverage/ 没被 ignore,Cursor 把它们一并索引。embedding 检索时,编译后的 JS 经常因为”包含一样的关键字”被判定相关,反而压过真正的 src/ 源码。
如何判断:执行后看 Cursor 回复底部的 “Context used”,里面出现 dist/、build/、.next/、out/、.astro/ 任意一个路径就是命中。
2. Vendored 第三方库放在仓库里
旧式 Node / PHP 项目里 vendor/ 直接 commit;前端项目偶尔有 public/vendor/jquery-3.5.1.min.js。这些代码体量大、命中率高,把 agent 的 context 挤满。
如何判断:du -sh vendor/ public/vendor/ third_party/ 2>/dev/null,若任一目录 > 5MB 又被索引,就是元凶。
3. 完全没有 .cursorignore
很多人以为 .gitignore 就够了,但 .gitignore 不管未被 git 追踪的本地文件——比如 .env.local、scratch.md、old-backup-2024.tsx。Cursor 看见就会索引。
如何判断:仓库根执行 ls -la | grep -E "(scratch|backup|old|\.bak|\.orig)",列出来的文件如果不在 .cursorignore 里,都是潜在污染源。
4. 备份与 .bak / .orig 文件
merge 冲突遗留的 Foo.tsx.orig、IDE 自动保存的 Foo.tsx~、或者你手动复制的 Foo-old.tsx。这些文件和当前版本只差几行,embedding 算它们高度相关,agent 经常把旧逻辑搬回来。
如何判断:find . -type f \( -name "*.orig" -o -name "*.bak" -o -name "*~" -o -name "*-old.*" \) | head -20。
5. 测试 fixtures / snapshot 抢戏
__snapshots__/、fixtures/、mocks/ 经常和真实代码”语义雷同但行为不同”。改业务逻辑时,agent 把 snapshot 里的旧字符串误认为是当前代码的真实状态。
如何判断:在 “Context used” 里看到 __snapshots__ 或 .snap 文件,且你的 prompt 跟测试无关,就是。
最短修复路径
Step 1:建一个能拦住常见污染源的 .cursorignore
在仓库根创建或扩充 .cursorignore:
# 构建产物
dist/
build/
out/
.next/
.astro/
.svelte-kit/
.nuxt/
# 依赖与 vendored
node_modules/
vendor/
public/vendor/
third_party/
# 缓存、覆盖率、日志
.cache/
.turbo/
.parcel-cache/
coverage/
*.log
# 备份与编辑器临时文件
*.bak
*.orig
*~
*-old.*
*.swp
# 压缩 / 打包文件
*.min.js
*.min.css
*.bundle.js
*.bundle.css
# 测试 snapshot(按需)
**/__snapshots__/
**/*.snap
# 本地 scratch
scratch.md
TODO.local.md
根据栈微调,原则是”AI 看到没价值/会误导的,全屏蔽”。
Step 2:强制 Cursor 重建索引
.cursorignore 改完不会立刻生效,必须 resync:
Cmd+Shift+P → "Cursor: Resync Index"
或者更彻底地:
# 关闭 Cursor,然后
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*/cursorIndex
# 重启 Cursor
重建完成后,Settings → Codebase Indexing 显示的 “Files Indexed” 数应该明显下降。
Step 3:在 prompt 里用 @File / @Folder 锁定要参考的文件
即使 ignore 干净了,长 chat 仍会偶发误检索。最稳妥的做法是显式钉:
@Folder src/components/auth @File src/lib/auth.ts
修改 AuthForm 组件的 onSubmit。只读 / 改我 @ 出来的文件,
不要参考任何 dist/、build/ 或 *.min.js 的内容。
加一句反向约束(“不要参考 X”)通常比只加正向约束更有效。
Step 4:定期清理仓库里的”考古层”
每月(或加到 pre-commit hook)跑一次清扫:
# 列出所有可能被 agent 误读的文件
find . -type f \( \
-name "*.bak" -o -name "*.orig" -o -name "*~" \
-o -name "*-old.*" -o -name "*-backup.*" \
-o -name "*.swp" \
\) -not -path "./node_modules/*" -not -path "./.git/*"
# 确认无用后删
find . -type f \( -name "*.bak" -o -name "*.orig" -o -name "*~" \) \
-not -path "./node_modules/*" -delete
合并冲突后第一时间 git status 看是否产生了 .orig,立刻删。
Step 5:验证 agent 现在读对了
让 Cursor 自己列读取的文件:
列出你为了回答上一个 prompt 读了哪些文件,完整路径,按读取
顺序。不要包含 dist / vendor / *.min.js。如果有,告诉我哪个 @ 把它们带进来了。
回答里若仍出现脏路径,说明 ignore 不完整,回 Step 1 补。
预防建议
- 新仓库初始化时就 commit
.cursorignore,模板和.gitignore同步维护 - 生成产物(
dist/、build/、coverage/)永远放仓库根独立目录,不要散落在src/里 - vendored 第三方代码放
third_party/并加进.cursorignore,不要直接放仓库根或public/ - 解决 merge 冲突后立刻
find . -name "*.orig" -delete,避免污染索引 - 在 CLAUDE.md /
.cursorrules里写一句 “Treat dist/, build/, vendor/, and .min. as build artifacts. Never read them.”