Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ cdidx status --check --json
cdidx search "handleRequest"
cdidx definition UserService
cdidx search "Handle" --project MyApp
cdidx search "File.ReadAllText" --exact-substring --reject-before "Length" --guard-window 8
cdidx validate
cdidx mcp
cdidx lsp --db .cdidx/codeindex.db
Expand Down Expand Up @@ -350,6 +351,7 @@ cdidx status --check --json
cdidx search "handleRequest"
cdidx definition UserService
cdidx search "Handle" --project MyApp
cdidx search "File.ReadAllText" --exact-substring --reject-before "Length" --guard-window 8
cdidx validate
cdidx mcp
cdidx lsp --db .cdidx/codeindex.db
Expand Down
18 changes: 18 additions & 0 deletions USER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,8 @@ cdidx search "計算" --prefix # widen every token to
cdidx search "content:auth*" --fts # raw FTS5 syntax; `content:` is the only valid column qualifier, and NEAR distance is capped at 100
cdidx search "Run();" --exact-substring # case-sensitive exact substring, no FTS5
cdidx search "Foo.Bar" --lang csharp --exact-substring # Java/Kotlin/C# exact search/find canonicalizes escaped source identifiers
cdidx search "File.ReadAllText" --exact-substring --reject-before "Length" --guard-window 8 # API calls missing a nearby preceding guard
cdidx search "FileMode.Create" --exact-substring --require-after "File.Move" --guard-window 12 # require a nearby follow-up action
cdidx search "--open-reports" --path README.md --count # quoted literal that starts with --
cdidx search --query "--path" --path README.md # search for an option-looking literal
```
Expand All @@ -825,6 +827,14 @@ Search normalizes literal FTS queries to Unicode NFC before matching. If every
literal token exceeds SQLite FTS5 unicode61's 1000-character token cap,
zero-result JSON includes `query_degraded_reason` and `tokens_dropped`. Index
validation reports long unbroken FTS tokens as `fts_token_too_long`.
Guard-aware search filters primary `search` matches by nearby literal guards:
`--require-before` / `--require-after` keep matches only when the guard query
appears in the selected line window, while `--reject-before` / `--reject-after`
drop matches when the guard query appears. JSON search results include
`guard_evidence` for required guards that matched.
The MCP `search` tool exposes the same mode as camelCase arguments:
`requireBefore`, `requireAfter`, `rejectBefore`, `rejectAfter`, and
`guardWindow`.

### Debugging queries

Expand Down Expand Up @@ -2933,6 +2943,8 @@ cdidx search "計算" --prefix # クエリ全体を p
cdidx search "content:auth*" --fts # 生のFTS5構文。列修飾子は `content:` だけが有効で、NEAR distance は 100 まで
cdidx search "Run();" --exact-substring # 大文字小文字区別の完全部分一致、FTS5 なし
cdidx search "Foo.Bar" --lang csharp --exact-substring # Java/Kotlin/C# の exact 検索 / find は escaped source identifier を正規化する
cdidx search "File.ReadAllText" --exact-substring --reject-before "Length" --guard-window 8 # 直前の guard がない API 呼び出し
cdidx search "FileMode.Create" --exact-substring --require-after "File.Move" --guard-window 12 # 近傍の後続処理を要求
cdidx search "--open-reports" --path README.md --count # `--` で始まる引用済みリテラル
cdidx search --query "--path" --path README.md # オプションに見えるリテラルを検索
```
Expand All @@ -2941,6 +2953,12 @@ literal FTS クエリは照合前に Unicode NFC へ正規化されます。す
token が SQLite FTS5 unicode61 の 1000 文字 token 上限を超える場合、0 件
JSON には `query_degraded_reason` と `tokens_dropped` が含まれます。index
validation は長い連続 FTS token を `fts_token_too_long` として報告します。
guard-aware search は primary の `search` 一致を近傍の literal guard で絞り込みます:
`--require-before` / `--require-after` は指定行窓内に guard query がある場合だけ残し、
`--reject-before` / `--reject-after` は guard query がある一致を落とします。JSON の検索結果には
一致した required guard の `guard_evidence` が含まれます。
MCP `search` tool では同じ mode を camelCase 引数 `requireBefore`, `requireAfter`,
`rejectBefore`, `rejectAfter`, `guardWindow` で指定できます。

### クエリのデバッグ

Expand Down
19 changes: 19 additions & 0 deletions changelog.d/unreleased/2852.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
category: added
issues:
- 2852
affected:
- src/CodeIndex/Database/DbSearchReader.cs
- src/CodeIndex/Cli/QueryCommandRunner.cs
- src/CodeIndex/Mcp/McpToolHandlers.cs
- src/CodeIndex/Mcp/McpToolDefinitions.cs
- USER_GUIDE.md
---

## English

- **Added guard-aware search filters (#2852)** — `cdidx search` and the MCP `search` tool can now keep or reject primary matches based on nearby literal guard queries with before/after guard constraints.

## 日本語

- **guard-aware search filter を追加しました (#2852)** — `cdidx search` と MCP `search` tool は、before/after の guard constraint により、primary の一致を近傍の literal guard query で残す / 除外できるようになりました。
5 changes: 5 additions & 0 deletions src/CodeIndex/Cli/CliFlagSchema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ private static IReadOnlyList<CliFlag> BuildAll()
new() { Name = "--exact-name", Description = "Exact symbol-name equality", Commands = Set(ExactNameCommands), AlsoAcceptedBy = Set("search") },
new() { Name = "--exact-substring", Description = "Search-only exact substring match", Commands = Set("search"), AlsoAcceptedBy = Set(ExactSubstringAccepted) },
new() { Name = "--prefix", Description = "Trailing-asterisk prefix shorthand", Commands = Set("search") },
new() { Name = "--require-before", ValuePlaceholder = "<query>", Description = "Search: require a nearby guard query before each primary match", Commands = Set("search") },
new() { Name = "--require-after", ValuePlaceholder = "<query>", Description = "Search: require a nearby guard query after each primary match", Commands = Set("search") },
new() { Name = "--reject-before", ValuePlaceholder = "<query>", Description = "Search: reject primary matches with a nearby guard query before them", Commands = Set("search") },
new() { Name = "--reject-after", ValuePlaceholder = "<query>", Description = "Search: reject primary matches with a nearby guard query after them", Commands = Set("search") },
new() { Name = "--guard-window", ValuePlaceholder = "<n>", Description = "Search: line window for require/reject guard queries", Commands = Set("search") },
new() { Name = "--no-progress", Description = "Disable animated progress and spinner output", Commands = Set(AllCommands.ToArray()) },
new() { Name = "--name", ValuePlaceholder = "<name>", Description = "Exact symbol name", Commands = Set("symbols") },
new() { Name = "--max-line-width", ValuePlaceholder = "<n>", Description = "Clamp long single-line payloads (0 disables clamping)", Commands = Set(MaxLineWidthCommands) },
Expand Down
6 changes: 5 additions & 1 deletion src/CodeIndex/Cli/ConsoleUi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ private static readonly (string Command, string Usage)[] CommandUsageLines =
("index-commits", "cdidx index <projectPath> --commits <commit-ref> [commit-ref ...] [--db <path>] [--verbose] [--dry-run] [--json] [--memory-trace] [--duration-format <auto|seconds|hms>] [--max-file-bytes <bytes>] [--include-symbol-kind <kind>[,<kind>]] [--exclude-symbol-kind <kind>[,<kind>]]"),
("index-changed-between", "cdidx index <projectPath> --changed-between <old-ref> <new-ref> [--db <path>] [--verbose] [--dry-run] [--json] [--memory-trace] [--duration-format <auto|seconds|hms>] [--max-file-bytes <bytes>] [--include-symbol-kind <kind>[,<kind>]] [--exclude-symbol-kind <kind>[,<kind>]]"),
("index-files", "cdidx index <projectPath> --files <path> [path ...] [--db <path>] [--verbose] [--dry-run] [--json] [--memory-trace] [--duration-format <auto|seconds|hms>] [--max-file-bytes <bytes>] [--include-symbol-kind <kind>[,<kind>]] [--exclude-symbol-kind <kind>[,<kind>]]"),
("search", "cdidx search <query>|--query <query>|-- <query> [--db <path>] [--json[=ndjson|array]] [--format <text|json|count|compact|csv|tsv|lsp|qf|sarif>] [--verbose] [--limit <n>|--top <n>] [--lang <lang>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--snippet-lines <n>] [--snippet-focus <leftmost|quality|proximity>] [--max-line-width <n>] [--fts] [--exact|--exact-substring] [--prefix] [--count] [--since <datetime>] [--no-dedup] [--no-visibility-rank]"),
("search", "cdidx search <query>|--query <query>|-- <query> [--db <path>] [--json[=ndjson|array]] [--format <text|json|count|compact|csv|tsv|lsp|qf|sarif>] [--verbose] [--limit <n>|--top <n>] [--lang <lang>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--snippet-lines <n>] [--snippet-focus <leftmost|quality|proximity>] [--max-line-width <n>] [--fts] [--exact|--exact-substring] [--prefix] [--count] [--since <datetime>] [--no-dedup] [--no-visibility-rank] [--require-before <query>] [--require-after <query>] [--reject-before <query>] [--reject-after <query>] [--guard-window <n>]"),
("definition", "cdidx definition <query>|--query <query>|-- <query> [--db <path>] [--json] [--format <text|json|count|compact|csv|tsv|lsp|qf|sarif>] [--verbose] [--limit <n>|--top <n>] [--lang <lang>] [--kind <kind>] [--visibility <v[,v]>] [--exclude-visibility <v[,v]>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--body] [--exact|--exact-name] [--count] [--since <datetime>]"),
("goto", "cdidx goto <query>|--query <query>|-- <query> [--db <path>] [--json] [--limit <n>|--top <n>] [--lang <lang>] [--kind <kind>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--exact|--exact-name] [--all]"),
("references", "cdidx references <query>|--query <query>|-- <query> [--db <path>] [--json] [--format <text|json|count|compact|csv|tsv|lsp|qf|sarif>] [--verbose] [--limit <n>|--top <n>] [--lang <lang>] [--kind <kind>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--body] [--snippet-lines <n>] [--max-line-width <n>] [--exact|--exact-name] [--count]"),
Expand Down Expand Up @@ -980,6 +980,8 @@ private static void PrintFlagReference(Action<string> WriteHelpLine)
WriteHelpLine(" --count Count only; search/definition/references/callers/callees/symbols/files/find/unused ignore --limit, impact/hotspots still use visible page counts");
Console.WriteLine(" --since <datetime> Filter to files modified since this timestamp (ISO 8601)");
Console.WriteLine(" --no-dedup search only: return every raw overlapping chunk hit (debug/density)");
WriteHelpLine($" --require-before/--require-after <query> search only: keep primary matches only when the guard query appears within --guard-window lines before/after the match (default {DbReader.DefaultSearchGuardWindow}, max {DbReader.MaxSearchGuardWindow})");
WriteHelpLine(" --reject-before/--reject-after <query> search only: drop primary matches when the guard query appears within the same before/after window; useful for finding API calls missing nearby checks");
Console.WriteLine(" --bytes Show raw byte counts in human output for files/map instead of binary units; JSON always keeps raw integer bytes");
Console.WriteLine(" --min-entrypoint-confidence <n> map only: omit entrypoint candidates below this 0.0..1.0 confidence");
WriteHelpLine(" --max-hops <n> Max BFS hops for impact analysis, inclusive (default: 5; --max-hops 2 returns callers at hop 1 and 2; --max-hops 0 resolves the symbol without traversing callers)");
Expand Down Expand Up @@ -1012,6 +1014,8 @@ private static void PrintExamples()
Console.WriteLine(" cdidx search \"auth*\" Prefix shorthand in literal-safe mode");
Console.WriteLine(" cdidx search --query --path --path README.md Search for a literal option token");
Console.WriteLine(" cdidx search \"Run();\" --exact-substring Case-sensitive exact substring search");
Console.WriteLine(" cdidx search \"File.ReadAllText\" --exact-substring --reject-before \"Length\" --guard-window 8");
Console.WriteLine(" Find calls without a nearby preceding size guard");
Console.WriteLine(" cdidx search authenticate --json=array Emit search results as one JSON array");
Console.WriteLine(" cdidx search authenticate --profile Append SQL profile JSON for slow-query debugging");
Console.WriteLine(" cdidx search authenticate --verbose Emit query debug diagnostics on stderr");
Expand Down
2 changes: 2 additions & 0 deletions src/CodeIndex/Cli/JsonOutputContracts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ internal sealed record VersionInfoJsonResult(
[JsonSerializable(typeof(RepoModuleResult))]
[JsonSerializable(typeof(ReportBundleSummary))]
[JsonSerializable(typeof(SearchHighlight))]
[JsonSerializable(typeof(SearchGuardEvidence))]
[JsonSerializable(typeof(List<SearchGuardEvidence>))]
[JsonSerializable(typeof(SearchQueryHint))]
[JsonSerializable(typeof(SearchResult))]
[JsonSerializable(typeof(SearchTermOccurrence))]
Expand Down
Loading
Loading