Skip to content

[Feature]: 多 git 子仓库的大型 workspace(如 vllm + 插件)下 Flashgrep 无法正常工作:根目录无 git 基线导致索引不可用,进入子仓库则丢失关联仓库搜索范围 #2306

Description

@Raing5Days

Summary

当一个 workspace 是大型聚合目录——本身不是 git 仓库,内部包含多个独立 git 仓库(例如 vllm 主仓库 + 若干插件/关联仓库,统一在一个 workspace 下开发):

workspace/                  ← 非 git 仓库(聚合根)
├── git仓库1/               ← 独立 repo(如 vllm)
├── git仓库2/               ← 独立 repo(如 vllm-engine 插件)
└── git仓库3/               ← 独立 repo(如推理插件)

此时 Flashgrep 索引搜索两条路都走不通:

  1. 以整个 workspace 为 repo 打开:flashgrep 的索引模型依赖 git 基线(base-snapshot 绑定 commit),而聚合根不是 git 仓库 → 无法建立基线 → 索引不可用(Grep 退化为全量扫描,Glob 无 fallback 直接受影响)。
  2. 进入某个子仓库打开:搜索 scope 被强制限定在该 repo 内(越界直接报 "Search path is outside workspace root")→ 搜不到同 workspace 下其他关联仓库 → 丢失跨仓库搜索能力。

根因是 flashgrep 的集成模型是单仓库的(一次搜索请求只带一个 repo_id,scope 必须落在该 repo 内),而产品需要的是多仓库聚合 workspace 场景。

  • 类型: Bug / 能力缺失(对多 git 子仓库 workspace 布局的支持)
  • 严重度: 中~高(影响 monorepo/多仓库布局用户的 Grep/Glob,表现为搜不到或降级)
  • 影响面: 桌面端 Glob/Grep 工具(本地 workspace),多 git 子仓库布局用户

Area

Desktop app

Reproduction or evidence

复现步骤:

  1. 建立如上目录结构:聚合根 workspace/ 不是 git 仓库,内部 git仓库1/git仓库2/ 各自 git init
  2. 开启 app.ai_experience.enable_workspace_search,以 workspace/ 为工作目录打开。
  3. 调用 Grep/Glob 搜索跨仓库内容(如同时分布在两个子仓库的符号)。
  4. 观察:
    • 以 workspace 根为 repo 打开时,索引停留在 MissingBaseSnapshot/扫描降级(Grep 慢或结果不完整;Glob 依赖索引目录,行为异常,与 #TODO 关联的超时问题互相放大)。
    • 把 workspace 切到 git仓库1/ 打开时,能搜到仓库 1 内部,但搜索 git仓库2/ 路径直接报越界/无结果——丢失关联仓库权限。

代码证据(单仓库模型的绑定点)

位置 事实
flashgrep/protocol.rs:105-119 SearchParams { repo_id, ... }GlobParams { repo_id, scope }——一次搜索请求只携带单个 repo_id,无跨仓库聚合字段
flashgrep/protocol.rs:357-374 RepoStatus 的索引状态是单仓库语义:base_snapshot_root / snapshot_key / dirty_files{modified,deleted,new} / rebuild_recommended——基线绑定 git commit
flashgrep/protocol.rs:378-386 RepoPhase::MissingBaseSnapshot——无可用 git 基线时索引不可用,是显式状态
workspace_search/service.rs:78,435 sessions: HashMap<PathBuf, SessionEntry>get_or_open_session(repo_root)——session 以单个 repo_root 为键,一次搜索只打开/查询一个 repo
workspace_search/service.rs:906-921 normalize_scope_pathnormalized.starts_with(repo_root) 否则报 "Search path is outside workspace root"——scope 硬性限定在单 repo 内,跨仓库路径被拒绝
workspace_search/service.rs:226 Grep 搜索带 with_scan_fallback(true)——可降级扫描;GlobParams(protocol.rs:115-119)无 fallback 字段,Glob 无降级路径
grep_tool.rs:270-274 工具层把 context.workspace.root_path_string() 整体当作 repo_root 传参——整个 workspace 被当成一个 repo,多子仓库结构被压平
glob_tool.rs:419-426 GlobSearchRequest { repo_root: workspace_root, ... }——同上,整个 workspace 当单个 repo
flashgrep/rpc_client.rs:340 daemon 能力声明 "workspace_list": false——daemon 不支持列出 workspace 内多仓库并聚合
resources/flashgrep/README.md:5 daemon 为外部项目 wgqqqqq/flashgrep v0.2.10,BitFun 侧为集成方;多仓库能力需在集成层解决

根因调用链

工具层 Grep/Glob
  → repo_root = workspace 聚合根(非 git 仓库)
  → WorkspaceSearchService::search_content/glob
  → get_or_open_session(workspace_root)   // 单 repo session
  → normalize_scope_path:scope 必须 starts_with(repo_root)   // 跨子仓库路径被拒
  → daemon:无 git 基线 → MissingBaseSnapshot → 索引不可用/降级

两个方向的矛盾:

  1. 把 workspace 根当 repo:flashgrep 索引模型要求 git 基线(base-snapshot 绑定 commit、dirty 分类来自 git status、语料遵循 .gitignore),聚合根不是 git 仓库时基线缺失;即便强行索引,也会重复扫描内部子仓库并撞上子仓库各自的 .gitignore 边界。
  2. 把子仓库当 repo:scope 被 starts_with(repo_root) 强制锁死在单仓库内,同 workspace 的其他关联仓库(插件等)不可搜索——正是「进入某个仓库就失去外部其他关联仓库的权限」。

工具层没有任何跨仓库聚合逻辑:不枚举 workspace 下的子仓库、不开多个 repo session 并发查询、不合并结果。一次 Grep/Glob 只能命中一个 repo_root。

Expected behavior

多 git 子仓库的聚合 workspace 应被当作仓库集合处理,而不是单个 repo:

  1. 仓库集合抽象:workspace 是多个 git 仓库的组合。搜索请求支持 repo_ids: Vec<String>(或聚合根 + 子仓库发现),daemon 或服务层按子仓库建索引并聚合结果,去重后返回。
  2. 子仓库自动发现:服务层识别 workspace 内的 git 子仓库边界(git rev-parse --show-toplevel.git 目录发现),每个子仓库一个 repo session;跨仓库 Grep/Glob 并发查询各 session 后合并。
  3. scope 语义扩展:搜索路径允许跨多个子仓库,越界检查从「单 repo 内」放宽为「任一子仓库内」,并保留权限边界(子仓库外仍拒绝)。
  4. 无 git 基线的降级路径:聚合根非 git 时,Grep 的 scan fallback 需显式告知用户「索引不可用、正在全量扫描」;Glob 需要补齐 fallback(当前无)。
  5. 避免重复扫描:子仓库边界识别后,聚合根扫描应跳过嵌套 .git 目录与子仓库内部,防止重复索引。

建议方案

  • 短期(集成层)WorkspaceSearchService 增加 workspace → 子仓库集合的映射;Grep/Glob 工具对跨仓库请求并发调用各子仓库 session 并合并结果;scope 越界检查按仓库集合判定。
  • 中期(协议层):与外部 wgqqqqq/flashgrep 上游对齐多仓库能力(workspace_list、多 repo 搜索参数),或引入聚合根索引模式(非 git 目录也可建不依赖 commit 的文件快照基线)。
  • 配套:与本仓库 #TODO(Flashgrep RPC 调用链无超时)联动——多仓库并发查询放大了 daemon 单请求挂起的影响,修复时须一并加上超时与降级。

Environment, if relevant

BitFun commit: 4d3869859 (2026-08-14)
OS: Windows x64
FLASHGREP_DAEMON_BIN: C:\Users\wfwt\AppData\Local\BitFun\flashgrep\flashgrep-x86_64-pc-windows-msvc.exe
flashgrep daemon: wgqqqqq/flashgrep v0.2.10(外部项目,本仓库集成)
布局: workspace 聚合根(非 git)+ 多个独立 git 子仓库(主项目 + 插件)

Related files

  • src/crates/services/services-integrations/src/workspace_search/flashgrep/protocol.rs
  • src/crates/services/services-integrations/src/workspace_search/service.rs
  • src/crates/services/services-integrations/src/workspace_search/flashgrep/client.rs
  • src/crates/services/services-integrations/src/workspace_search/flashgrep/rpc_client.rs
  • src/crates/assembly/core/src/agentic/tools/implementations/grep_tool.rs
  • src/crates/assembly/core/src/agentic/tools/implementations/glob_tool.rs
  • src/crates/assembly/core/src/service/search/service.rs
  • resources/flashgrep/README.md

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions