你让 Cursor “把全项目的 useAuth 都改成 useSession”,结果它只改了 3 个文件,但 grep -r useAuth src/ 显示还剩 17 处。这不是模型偷懒,是它根本没”看见”剩下那 17 个文件——索引漏了、workspace 打开位置不对,或者你的 prompt 没把它指向正确目录。Cursor(以及 Windsurf、Cline 这类 IDE 集成 agent)只能修改”在 codebase index 里 + 在 chat context window 里”的文件,缺一个都漏。这篇给出诊断步骤和把项目重新”拉进 Cursor 视野”的具体命令。
常见原因
按命中率从高到低排序。
1. 索引排除了关键目录
Cursor 的 codebase index 受三层规则影响:.gitignore、.cursorignore,以及 Cursor 自己的”过大文件/隐藏目录”启发式跳过。最常见的踩坑是把整个 src/packages/ 或 apps/web/ 写进 .gitignore(比如旧的 monorepo 习惯),结果 Cursor 顺带也不索引了。
如何判断:在 Cursor 里按 Cmd+Shift+P → “Cursor Settings” → Features → Codebase Indexing,看显示的”Files Indexed”数。和 git ls-files | wc -l 对比,若差距超过 30%,说明大量文件被排除。
2. Workspace 打开的层级不对
你在 ~/projects/myapp/frontend/ 打开 Cursor,但后端代码、共享 types 在 ~/projects/myapp/backend/ 和 ~/projects/myapp/shared/。Cursor 只索引当前 workspace 根,看不到兄弟目录的内容,agent 自然无法跨包重构。
如何判断:在 Cursor 左下角看 workspace 名。若显示的是子目录而不是 monorepo 根,就是这种情况。
3. Prompt 没显式钉文件
即使索引完整,Cursor 在长 chat 里也会按”相关性 + token 预算”挑文件塞进 context window。如果你的 prompt 写得太抽象(“refactor the auth flow”),它会用 embedding 检索去找,但漏掉那些命名不直观或者注释不全的文件。
如何判断:执行后看 Cursor 给出的 “Context used” 折叠面板(在回复底部),列出它实际读过哪些文件。和你预期改动的文件清单对比。
4. .gitignore 中包含了运行时生成但仍要被 AI 看到的文件
比如 src/generated/ 或 prisma/client/ 这种由 build 产生但语义上很重要的类型定义,常被一并 ignore,然后 agent 改 query 时不知道字段名。
如何判断:搜 grep -r "from.*generated" src/,若代码大量从 generated 目录 import,但 .gitignore 把它排掉了,Cursor 就读不到。
5. 大文件被自动跳过
Cursor 对 > 500KB 或 > 5000 行的单文件默认不索引(避免拖慢检索)。如果你的 schema、迁移脚本或 i18n 字典是巨型单文件,agent 经常表现为”完全不知道这个文件存在”。
如何判断:find src -type f -size +500k,把列出来的文件名贴回 chat 问 Cursor “do you see this file in your index?”
最短修复路径
按收益从高到低,前 3 步通常足够。
Step 1:核对 Codebase Index 范围
打开 Cursor → Cmd+Shift+P → “Cursor Settings” → Features → Codebase Indexing。看:
- Files Indexed:和
git ls-files | wc -l比较 - Status:必须是 Synced,不是 Indexing 也不是 Stale
- Ignore Rules:会显示生效的
.gitignore+.cursorignore
如果 Files Indexed 明显偏少,临时把可疑的 ignore 行注释掉,再点 “Resync Index”。命令行也可以一键重建:
# 关掉 Cursor 后清掉索引缓存
rm -rf ~/Library/Application\ Support/Cursor/User/workspaceStorage/*/cursorIndex
# 重启 Cursor,让它从零重建
Step 2:从 monorepo 根目录重开 workspace
如果你在子目录里打开,直接 File → Open Folder 重选根目录。或在终端:
cd ~/projects/myapp # monorepo 根
cursor . # 用根目录重启 Cursor
打开后,在 chat 里输入 @Folder frontend 和 @Folder backend 各自验证一次,确认两边都能被引用到。
Step 3:Prompt 里显式钉住文件 / 目录
不要写”修改 auth 相关逻辑”,改写成:
@File src/lib/auth.ts @File src/hooks/useAuth.ts @Folder src/components/auth
把 useAuth 替换为 useSession。只动我 @ 出来的文件 + 这些文件
的直接调用方。改完后列出所有被改的文件路径。
@File / @Folder / @Symbol 是硬钉子,比依赖 embedding 检索可靠得多。Claude Code 用户对应的是在 CLAUDE.md 里写死”always read these files first”。
Step 4:维护一个干净的 .cursorignore
.cursorignore 语法和 .gitignore 一样,但只影响 Cursor。典型模板:
# 构建产物
dist/
build/
.next/
.astro/
out/
# 依赖
node_modules/
vendor/
# 缓存与日志
.cache/
.turbo/
*.log
coverage/
# 大型生成数据(按需)
**/*.snap
public/locales/*.json
不要把 src/generated/ 一类语义上必要的目录写进去——它们是 agent 推理类型时的关键依据。
Step 5:把大文件拆成可索引的规模
如果某文件超过 5000 行,agent 几乎一定漏。把 i18n、schema、route 表按模块拆开:
# 例:把 4 万行的 src/i18n/zh.json 按 namespace 拆
node scripts/split-i18n.mjs src/i18n/zh.json src/i18n/zh/
拆完更新 import,再 Resync Index。
预防建议
- 在仓库根加一份最小的
.cursorignore,只屏蔽构建产物和依赖,绝不屏蔽src/generated/、schema、迁移脚本 - 大改动前先写一行 “files I expect to be touched: a.ts, b.ts, c.ts” 让 agent 反过来确认它能不能 @ 到全部
- monorepo 始终从仓库根打开 Cursor,子包用
@Folder packages/foo限定,而不是单独打开子目录 - 单文件超过 3000 行时主动拆分;不可拆的(如自动生成的 schema)在 CLAUDE.md /
.cursorrules里点名说明 - 每次重大依赖升级或目录结构调整后,手动点一次 “Resync Codebase Index”,别等 Cursor 自己发现