Cursor 没读到整个项目:原因排查 + 修复路径

Cursor 只能改它能看见的文件。修好索引范围、从仓库根打开、用 @ 显式钉住文件即可。

你让 Cursor “把全项目的 useAuth 都改成 useSession”,结果它只动了 3 个文件,但 grep -rn useAuth src/ 显示还剩 17 处。这不是模型偷懒,是它根本没”看见”剩下那 17 个文件——可能索引漏了、workspace 打开层级不对,或者你的 prompt 没把它指向正确目录。Cursor(以及 Windsurf、Cline 这类 IDE 集成 agent)只能修改”既在 codebase index 里、又在 chat context window 里”的文件,缺一个都漏。

最快的修法: 打开 chat,对每个要改的目录敲 @Folder、对关键文件敲 @File,然后在 prompt 末尾加一句”list every file path you changed”。@ 硬钉子会完全绕过 embedding 检索,是最可靠的一招。如果连 @Folder 都列不出文件,那问题出在索引上,直接跳到 Step 1

先判断你属于哪一类

现象最可能的原因跳到
@Folder x 列不出文件,或比实际少很多该目录被 .gitignore / .cursorignore 排除出索引Step 1
左下角 workspace 名是子目录,不是仓库根打开层级不对Step 2
索引看着完整,但 agent 还是漏文件prompt 靠检索、没显式钉文件Step 3
agent 凭空猜字段名 / 类型名语义上必需的目录被 ignore 了Step 4
某个巨型文件(schema、i18n、迁移)像不存在一样文件超过单文件索引大小上限Step 5

常见原因

按命中率从高到低排序。

1. 索引排除了关键目录

Cursor 的 codebase index 受四层规则影响:.gitignore.cursorignore.cursorindexingignore,以及 Cursor 内置的默认 ignore 列表(node_modules、lockfile、构建产物、二进制和媒体文件默认就跳过)。最常见的踩坑是把整个 src/packages/apps/web/ 写进 .gitignore(旧 monorepo 习惯),结果 Cursor 顺带也不索引了——因为它会”automatically ignores files in .gitignore and the default ignore list”。

如何判断:在 Cursor 里按 Cmd+Shift+P → “Cursor Settings” → Indexing(旧版本在 Features → Codebase Indexing),看已索引文件数。和 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 折叠面板(“Context used”),它列出实际读过哪些文件。和你预期改动的文件清单对比。

4. 某条 ignore 规则挡住了 agent 仍需要的文件

src/generated/prisma/client/ 这种由 build 产生、但语义上很关键的类型定义,常被一并 ignore,于是 agent 改 query 时不知道字段名、类型名。

如何判断grep -rn "from.*generated" src/,若代码大量从 generated 目录 import,但某条 ignore 规则把它排掉了,Cursor 就读不到。

5. 大文件被自动跳过

为了让检索更快,Cursor 会跳过超过单文件索引大小上限的文件(截至 2026 年 6 月,默认 1 MB / 1048576 字节)。如果你的 schema、迁移脚本或 i18n 字典是个超过上限的巨型单文件,agent 经常表现为”完全不知道这个文件存在”。

如何判断find src -type f -size +1M,把列出来的文件贴回 chat 问 Cursor “do you see this file in your index?”

最短修复路径

按收益从高到低,前 3 步通常足够。

Step 1:核对 Codebase Index 范围

打开 Cursor → Cmd+Shift+P → “Cursor Settings” → Indexing(旧版本在 Features → Codebase Indexing)。看:

  • 已索引文件数:和 git ls-files | wc -l 对比
  • Status:应是已完成 / 已同步的状态,不是 “Indexing” 也不是 “Stale”。语义检索要到约 80% 完成度才可用,所以进度条卡住就意味着上下文不全。
  • Ignore 规则:面板会反映生效的 .gitignore + .cursorignore + .cursorindexingignore

索引大约每 5 分钟自动同步一次、只处理改动过的文件,所以大规模挪目录后它可能滞后。如果已索引数明显偏少,临时把可疑的 ignore 行注释掉,再触发重建:Cmd+Shift+PReindex Codebase,或点 Settings → Indexing 里的重建按钮。命令行也可以强制干净重建:

# 关掉 Cursor 后清掉 workspace 索引缓存
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 1)。

Step 3:Prompt 里显式钉住文件 / 目录

不要写”修改 auth 相关逻辑”,改写成:

@File src/lib/auth.ts @File src/hooks/useAuth.ts @Folder src/components/auth

把 useAuth 替换为 useSession。只动我 @ 出来的文件 + 这些文件
的直接调用方。改完后列出所有被改的文件路径。

@File / @Folder / @Symbol 是硬钉子,比依赖 embedding 检索可靠得多。@Folder 的目标要尽量小:大约 10 个文件以内的文件夹能干净塞进去,钉一个巨型目录会冲爆 context 预算,Cursor 反而只会抽样读。需要全项目级别的提问时可以退而用 @Codebase,但精确重构还是显式钉文件最稳。Claude Code 用户对应的做法是在 CLAUDE.md 里写死 “always read these files first”。

Step 4:维护精简的 ignore 集合,同时让 generated 代码仍可引用

.cursorignore 语法和 .gitignore 一样,但只影响 Cursor。一个合理的 .cursorignore

# 构建产物
dist/
build/
.next/
.astro/
out/

# 依赖
node_modules/
vendor/

# 缓存与日志
.cache/
.turbo/
*.log
coverage/

# 大型生成数据(按需)
**/*.snap
public/locales/*.json

要分清两个 ignore 文件的区别,它们行为不同:

  • .cursorignore 会把文件挡在所有 AI 功能之外(semantic search、Tab、Agent、Inline Edit)外加索引。它适合放纯噪声。
  • .cursorindexingignore 把文件排除出索引。这些文件不会出现在 codebase 搜索里,但仍能用 @File 引用到。偶尔需要钉、又不想撑大索引的大型 generated 目录,应该放这里。

不要把 src/generated/ 一类语义上必要的目录写进 .cursorignore(否则 agent 完全看不到它)。如果它大到不适合索引,就改放 .cursorindexingignore,需要时用 @File 钉进来。

Step 5:调高大小上限,或把文件拆开

如果某个单文件超过单文件索引上限(默认 1 MB),agent 会跳过它。两个选择。

settings.json 里调高上限(Cmd+Shift+P → “Preferences: Open User Settings (JSON)”):

{
  "cursor.maxFileSize": 2097152
}

或把 i18n、schema、route 表按模块拆开,让每一块都能干净索引:

# 例:把较大的 src/i18n/zh.json 按 namespace 拆开
node scripts/split-i18n.mjs src/i18n/zh.json src/i18n/zh/

拆完更新 import,再 Reindex Codebase

如何确认已修好

  1. Settings → Indexing 里,已索引文件数与 git ls-files | wc -l 相差在 5% 以内,且状态为已同步。
  2. chat 里对每个相关目录敲 @Folder,都能列出你预期的文件(没有空选择器)。
  3. 用显式 @ 钉子 + “list every file you changed” 重跑一遍重构,打印出的清单应与预期一致。
  4. 在命令行验证没有遗漏:grep -rn useAuth src/ 返回零结果(替换成你自己的符号)。较大的重构可以用 git diff --stat 核对每个该改的文件都改了。

预防建议

  • 在仓库根放一份最小.cursorignore,只屏蔽构建产物和依赖,绝不屏蔽 src/generated/、schema、迁移脚本。又大又必需的 generated 目录改放 .cursorindexingignore
  • 大改动前先写一行 “files I expect to be touched: a.ts, b.ts, c.ts”,让 agent 反过来确认它能不能 @ 到全部。
  • monorepo 始终从仓库根打开 Cursor,子包用 @Folder packages/foo 限定,而不是单独打开子目录。
  • 单文件接近 1 MB 索引上限时主动拆分;实在不可拆的(如自动生成的 schema)在 CLAUDE.md / .cursorrules 里点名说明,并用 @File 钉进来。
  • 每次重大依赖升级或目录结构调整后,手动跑一次 Reindex Codebase,别等那 5 分钟左右的自动同步。

两个 ignore 文件的最新、确切行为,以及默认 ignore 列表,可查 Cursor 官方文档:Ignore filesSemantic & agentic search

常见问题

为什么我让 Cursor 改的文件,它只改了一部分? 因为它只看见了一部分。文件必须既在 codebase index 里、又被拉进 chat 的 context window,才能被改。修法是把剩下的文件用 @File / @Folder 钉进来,并在 Settings → Indexing 里确认它们已被索引。

.cursorignore.cursorindexingignore 有什么区别? .cursorignore 把文件挡在所有 AI 功能(semantic search、Tab、Agent、Inline Edit)和索引之外。.cursorindexingignore 只把它排除出索引,你仍能用 @File 手动引用。需要偶尔引用的大型 generated 代码就用后者。

怎么强制 Cursor 重新索引? Cmd+Shift+P(或 Ctrl+Shift+P)→ Reindex Codebase,或用 Cursor Settings → Indexing 里的重建按钮。要彻底重置就关掉 Cursor、删掉 workspace 索引缓存、再重启。

为什么一个大文件被忽略了? Cursor 会跳过超过单文件索引上限的文件(截至 2026 年 6 月默认 1 MB)。在 settings.json 里调高 cursor.maxFileSize,或把文件按模块拆开后重新索引。

@Folder 有大小限制吗? 没有硬上限,但大文件夹会撑爆 context 预算,于是 Cursor 改为抽样读取。大约 10 个文件以内的文件夹效果最好;更大的目录就只钉关键的那几个 @File

相关阅读

标签: #AI 编程 #排查 #排查 #Cursor