local-codebase-indexer 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. local_codebase_indexer-0.2.0/MANIFEST.in +5 -0
  2. local_codebase_indexer-0.2.0/PKG-INFO +118 -0
  3. local_codebase_indexer-0.2.0/README.md +83 -0
  4. local_codebase_indexer-0.2.0/README.zh-CN.md +83 -0
  5. local_codebase_indexer-0.2.0/README.zh-TW.md +83 -0
  6. local_codebase_indexer-0.2.0/TODO.md +30 -0
  7. local_codebase_indexer-0.2.0/benchmarks/README.md +35 -0
  8. local_codebase_indexer-0.2.0/benchmarks/baseline.json +1655 -0
  9. local_codebase_indexer-0.2.0/benchmarks/corpus/Auth/LoginService.cs +25 -0
  10. local_codebase_indexer-0.2.0/benchmarks/corpus/Controllers/LotController.cs +23 -0
  11. local_codebase_indexer-0.2.0/benchmarks/corpus/Controllers/ScrapController.cs +30 -0
  12. local_codebase_indexer-0.2.0/benchmarks/corpus/Data/MesDbContext.cs +17 -0
  13. local_codebase_indexer-0.2.0/benchmarks/corpus/Legacy/frmChangeLine.frm +19 -0
  14. local_codebase_indexer-0.2.0/benchmarks/corpus/Models/DrillBreakEvent.cs +12 -0
  15. local_codebase_indexer-0.2.0/benchmarks/corpus/Models/Lot.cs +13 -0
  16. local_codebase_indexer-0.2.0/benchmarks/corpus/Models/ScrapRecord.cs +11 -0
  17. local_codebase_indexer-0.2.0/benchmarks/corpus/Printing/LabelPrinter.cs +21 -0
  18. local_codebase_indexer-0.2.0/benchmarks/corpus/Repositories/LotRepository.cs +34 -0
  19. local_codebase_indexer-0.2.0/benchmarks/corpus/Repositories/ScrapRepository.cs +36 -0
  20. local_codebase_indexer-0.2.0/benchmarks/corpus/Services/IScrapService.cs +12 -0
  21. local_codebase_indexer-0.2.0/benchmarks/corpus/Services/InspectionService.cs +34 -0
  22. local_codebase_indexer-0.2.0/benchmarks/corpus/Services/LotService.cs +28 -0
  23. local_codebase_indexer-0.2.0/benchmarks/corpus/Services/ScrapService.cs +34 -0
  24. local_codebase_indexer-0.2.0/benchmarks/corpus/Sql/MES_Lot.sql +8 -0
  25. local_codebase_indexer-0.2.0/benchmarks/corpus/Sql/usp_Inspection_Report.sql +11 -0
  26. local_codebase_indexer-0.2.0/benchmarks/corpus/Sql/usp_Lot_UpdateStatus.sql +8 -0
  27. local_codebase_indexer-0.2.0/benchmarks/corpus/Sql/usp_Scrap_Insert.sql +12 -0
  28. local_codebase_indexer-0.2.0/benchmarks/corpus/Utils/DateRangeHelper.cs +14 -0
  29. local_codebase_indexer-0.2.0/benchmarks/corpus/Utils/PartNumberDecoder.cs +16 -0
  30. local_codebase_indexer-0.2.0/benchmarks/corpus/Web/scrapForm.ts +16 -0
  31. local_codebase_indexer-0.2.0/benchmarks/corpus/Web.config +9 -0
  32. local_codebase_indexer-0.2.0/benchmarks/corpus/tools/export_report.py +14 -0
  33. local_codebase_indexer-0.2.0/benchmarks/queries_stdlib.json +142 -0
  34. local_codebase_indexer-0.2.0/benchmarks/queries_synthetic.json +443 -0
  35. local_codebase_indexer-0.2.0/benchmarks/run_benchmark.py +214 -0
  36. local_codebase_indexer-0.2.0/index.md +132 -0
  37. local_codebase_indexer-0.2.0/local_codebase_indexer/__init__.py +3 -0
  38. local_codebase_indexer-0.2.0/local_codebase_indexer/__main__.py +5 -0
  39. local_codebase_indexer-0.2.0/local_codebase_indexer/callgraph.py +279 -0
  40. local_codebase_indexer-0.2.0/local_codebase_indexer/cli.py +122 -0
  41. local_codebase_indexer-0.2.0/local_codebase_indexer/core.py +323 -0
  42. local_codebase_indexer-0.2.0/local_codebase_indexer/cscalls.py +304 -0
  43. local_codebase_indexer-0.2.0/local_codebase_indexer/csdata.py +450 -0
  44. local_codebase_indexer-0.2.0/local_codebase_indexer/dataflow.py +250 -0
  45. local_codebase_indexer-0.2.0/local_codebase_indexer/db.py +194 -0
  46. local_codebase_indexer-0.2.0/local_codebase_indexer/embedder.py +137 -0
  47. local_codebase_indexer-0.2.0/local_codebase_indexer/langparse.py +569 -0
  48. local_codebase_indexer-0.2.0/local_codebase_indexer/mcp_server.py +136 -0
  49. local_codebase_indexer-0.2.0/local_codebase_indexer/query.py +756 -0
  50. local_codebase_indexer-0.2.0/local_codebase_indexer/scanner.py +101 -0
  51. local_codebase_indexer-0.2.0/local_codebase_indexer/sqlaccess.py +301 -0
  52. local_codebase_indexer-0.2.0/local_codebase_indexer/synonyms.py +101 -0
  53. local_codebase_indexer-0.2.0/local_codebase_indexer.egg-info/PKG-INFO +118 -0
  54. local_codebase_indexer-0.2.0/local_codebase_indexer.egg-info/SOURCES.txt +62 -0
  55. local_codebase_indexer-0.2.0/local_codebase_indexer.egg-info/dependency_links.txt +1 -0
  56. local_codebase_indexer-0.2.0/local_codebase_indexer.egg-info/entry_points.txt +2 -0
  57. local_codebase_indexer-0.2.0/local_codebase_indexer.egg-info/requires.txt +14 -0
  58. local_codebase_indexer-0.2.0/local_codebase_indexer.egg-info/top_level.txt +1 -0
  59. local_codebase_indexer-0.2.0/pyproject.toml +55 -0
  60. local_codebase_indexer-0.2.0/requirements.txt +10 -0
  61. local_codebase_indexer-0.2.0/setup.cfg +4 -0
  62. local_codebase_indexer-0.2.0/tests/test_dataaccess.py +114 -0
  63. local_codebase_indexer-0.2.0/tests/test_indexer.py +332 -0
  64. local_codebase_indexer-0.2.0/tests/test_onnx_plumbing.py +103 -0
@@ -0,0 +1,5 @@
1
+ include README*.md TODO.md index.md requirements.txt
2
+ graft tests
3
+ graft benchmarks
4
+ prune benchmarks/__pycache__
5
+ global-exclude __pycache__ *.pyc
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: local-codebase-indexer
3
+ Version: 0.2.0
4
+ Summary: Local codebase indexer and context provider for AI coding assistants: MCP server and CLI with SQL data-access and C# call relations. No cloud, no server.
5
+ Author: sfy257000
6
+ Project-URL: Homepage, https://github.com/sfy257000/local-codebase-indexer
7
+ Project-URL: Repository, https://github.com/sfy257000/local-codebase-indexer
8
+ Project-URL: Issues, https://github.com/sfy257000/local-codebase-indexer/issues
9
+ Keywords: mcp,model-context-protocol,claude-code,code-search,semantic-search,codebase-index,tree-sitter,sqlite,stored-procedure,csharp,dapper,t-sql,call-graph,ai-coding-assistant
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Topic :: Text Processing :: Indexing
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ Requires-Dist: tree-sitter>=0.23
24
+ Requires-Dist: tree-sitter-c-sharp
25
+ Requires-Dist: tree-sitter-python
26
+ Requires-Dist: tree-sitter-javascript
27
+ Requires-Dist: tree-sitter-typescript
28
+ Requires-Dist: numpy
29
+ Requires-Dist: pathspec
30
+ Provides-Extra: onnx
31
+ Requires-Dist: onnxruntime; extra == "onnx"
32
+ Requires-Dist: tokenizers; extra == "onnx"
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest; extra == "dev"
35
+
36
+ # Local Codebase Indexer
37
+
38
+ **English** | [繁體中文](README.zh-TW.md) | [简体中文](README.zh-CN.md)
39
+
40
+ A local codebase indexer and context provider for AI coding assistants (Claude Code via MCP, GitHub Copilot / Codex via CLI). It helps them navigate large legacy codebases with far fewer tokens. Everything is stored in `.ai_context/indexer.db` inside your project, with no cloud services involved. The design follows [`index.md`](index.md).
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ pip install local-codebase-indexer # Python 3.10+
46
+ # or, isolated from your other packages:
47
+ pipx install local-codebase-indexer
48
+ # optional real embeddings (see below): pip install "local-codebase-indexer[onnx]"
49
+ ```
50
+
51
+ From a clone: `pip install -e .` (the `bin/indexer` launcher still works in a checkout).
52
+
53
+ ## Usage (CLI)
54
+
55
+ ```bash
56
+ local-codebase-indexer --root <project> index # build / incrementally refresh the index (--force rebuilds all)
57
+ local-codebase-indexer search "database mapping for LotNo" --limit 5
58
+ local-codebase-indexer relations IExistOpenHandleService --direction both # upstream | downstream | both
59
+ local-codebase-indexer context Services/LotService.cs --lines 120 --padding 15 # alias: slice
60
+ local-codebase-indexer data-access MES_Lot # who reads / writes / executes a table or procedure; what a procedure touches
61
+ local-codebase-indexer stats
62
+ local-codebase-indexer status # is the index fresh? failed files, git commit, consistency checks
63
+ ```
64
+
65
+ - Without `--root` the current directory is used; `INDEXER_ROOT` also works.
66
+ - Put `--json` before the subcommand to get JSON output.
67
+ - `search`, `relations` and `context` run an incremental refresh first (mtime check, then md5 only when mtime changed).
68
+ - The tool names from the spec also work as subcommands: `codebase_semantic_search`, `codebase_get_symbol_relations`, `codebase_get_optimized_context` (options `--query`, `--symbol_name --relation_direction`, `--file_path --focus_lines --padding_lines`).
69
+
70
+ ## Usage (Claude Code / MCP)
71
+
72
+ ```bash
73
+ claude mcp add local-indexer -- local-codebase-indexer --root /path/to/project serve
74
+ # without installing: claude mcp add local-indexer -- uvx local-codebase-indexer --root /path/to/project serve
75
+ ```
76
+
77
+ `serve` speaks JSON-RPC (MCP) over stdio and exposes five tools: `codebase_semantic_search`, `codebase_get_symbol_relations`, `codebase_get_optimized_context`, `codebase_get_data_access`, `codebase_index_status`.
78
+
79
+ ## Three-layer index
80
+
81
+ | Layer | Implementation |
82
+ |---|---|
83
+ | Syntactic | tree-sitter for C#, Python, JavaScript, TypeScript/TSX; regex for SQL (PROCEDURE / VIEW / FUNCTION / TABLE); other text files (VB6 `.frm`, `.config`, `.md`, ...) are split into windowed chunks |
84
+ | Topology | `using` / `import` resolved to file dependencies, inheritance (base lists) and type usage (`invocation`), stored in the `dependencies` table |
85
+ | Semantic | 384-dim chunk embeddings in `vss_chunks`; queries fuse FTS5 keyword, symbol-name and vector rankings with Reciprocal Rank Fusion, then expand to the dependency neighbours of the top 3 files |
86
+
87
+ Encodings: UTF-8 first, then Big5, then cp1252. Files over 5MB are skipped. Root and nested `.gitignore` files are respected, and `.git`, `bin`, `obj`, `node_modules` and similar directories are always skipped.
88
+
89
+ ## Differences from the spec
90
+
91
+ - **Vector storage**: `sqlite-vss` needs a native extension and is no longer maintained, so `vss_chunks` stores float32 BLOBs and cosine similarity is computed with numpy. No extension to install.
92
+ - **Embedding model**: the default is a built-in hashing embedder (identifier sub-words, bigrams, CJK character bigrams). It is fast and reproducible but **does not understand synonyms**. For real transformer embeddings, export `all-MiniLM-L6-v2` or `bge-small-en-v1.5` to ONNX, install `onnxruntime` and `tokenizers`, and set `INDEXER_ONNX_MODEL=<folder with model.onnx and tokenizer.json>` (the loading, padding, pooling and re-index logic is covered by a test with a tiny synthetic model; retrieval quality with a real model has not been measured, so run `python benchmarks/run_benchmark.py --compare benchmarks/baseline.json` with the variable set to check it; mean pooling suits MiniLM, bge models recommend CLS pooling). Switching embedders triggers a full re-index.
93
+ - **Call relations** for C# are resolved with limited type inference (using / namespaces, field and constructor-injected types, locals, interface to implementation), and every edge carries a confidence: `confirmed` (the receiver type is known), `probable` (reached through an interface or a single candidate) or `candidate` (name match only). There is no Roslyn: no overload resolution by argument type, no delegates / lambdas / extension methods, and call chains are followed one level. Inheritance edges come from the AST and are reliable.
94
+ - Extra schema additions: `symbols.qualified_name`, `chunk_metadata.symbol_id`, and the `raw_refs`, `chunks_fts` and `meta` tables.
95
+
96
+ ## Data access (SQL)
97
+
98
+ `data-access <table-or-procedure>` answers "what writes / reads / executes X". It is built from T-SQL (INSERT / UPDATE / DELETE / MERGE / TRUNCATE / SELECT INTO / FROM / JOIN / EXEC, with alias resolution; CTEs, temp tables and system objects excluded), from C# SQL strings (literals, `+`, interpolation, `string.Format`, consts, locals) passed to Dapper, `SqlCommand` or EF `FromSql`, from stored-procedure names used with `CommandType.StoredProcedure`, and from EF `ToTable` / `[Table]` mappings. A procedure's callers are indirect writers of the tables it writes (followed up to 4 hops). Each entry has a confidence; **dynamic SQL (`EXEC(@sql)`, `sp_executesql`, SQL built from unknown values) cannot be resolved and is listed separately as `uncertain`**, never mixed into the confirmed lists. Known gaps: `FROM a JOIN b ON ..., c` loses `c`, and a stored-procedure name passed to a non-database method is not seen.
99
+
100
+ Natural-language search routes questions such as "who modifies MES_ScrapRecord" or "哪些程式會寫入 MES_Lot" to this index first.
101
+
102
+ ## Query expansion
103
+
104
+ Queries are expanded with a small synonym dictionary (`SP` / `預存程序` / `stored procedure` / `usp`, table, lot, scrap, ...; `local_codebase_indexer/synonyms.py`). Add or disable groups per project in `.ai_context/synonyms.json`: `{"groups": [["wpnlot", "在製批"]], "disable": ["sp"]}`. This helps abbreviations and Chinese/English terms, not free paraphrase.
105
+
106
+ ## Index health
107
+
108
+ `status` (also the MCP tool `codebase_index_status`) reports whether the index can be trusted without refreshing it: `fresh`, `stale` (files changed or git HEAD moved since the last update), `degraded` (failed files or an inconsistent database) or `not_indexed`. A file that fails to parse is removed from the index, listed with its error, and retried on every update, so search never returns stale lines for it. `index --force` rebuilds everything.
109
+
110
+ ## Benchmark
111
+
112
+ `python benchmarks/run_benchmark.py` measures Recall@5, Recall@10 and MRR on fixed queries. See [`benchmarks/README.md`](benchmarks/README.md).
113
+
114
+ ## Tests
115
+
116
+ ```bash
117
+ python -m pytest -q
118
+ ```
@@ -0,0 +1,83 @@
1
+ # Local Codebase Indexer
2
+
3
+ **English** | [繁體中文](README.zh-TW.md) | [简体中文](README.zh-CN.md)
4
+
5
+ A local codebase indexer and context provider for AI coding assistants (Claude Code via MCP, GitHub Copilot / Codex via CLI). It helps them navigate large legacy codebases with far fewer tokens. Everything is stored in `.ai_context/indexer.db` inside your project, with no cloud services involved. The design follows [`index.md`](index.md).
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install local-codebase-indexer # Python 3.10+
11
+ # or, isolated from your other packages:
12
+ pipx install local-codebase-indexer
13
+ # optional real embeddings (see below): pip install "local-codebase-indexer[onnx]"
14
+ ```
15
+
16
+ From a clone: `pip install -e .` (the `bin/indexer` launcher still works in a checkout).
17
+
18
+ ## Usage (CLI)
19
+
20
+ ```bash
21
+ local-codebase-indexer --root <project> index # build / incrementally refresh the index (--force rebuilds all)
22
+ local-codebase-indexer search "database mapping for LotNo" --limit 5
23
+ local-codebase-indexer relations IExistOpenHandleService --direction both # upstream | downstream | both
24
+ local-codebase-indexer context Services/LotService.cs --lines 120 --padding 15 # alias: slice
25
+ local-codebase-indexer data-access MES_Lot # who reads / writes / executes a table or procedure; what a procedure touches
26
+ local-codebase-indexer stats
27
+ local-codebase-indexer status # is the index fresh? failed files, git commit, consistency checks
28
+ ```
29
+
30
+ - Without `--root` the current directory is used; `INDEXER_ROOT` also works.
31
+ - Put `--json` before the subcommand to get JSON output.
32
+ - `search`, `relations` and `context` run an incremental refresh first (mtime check, then md5 only when mtime changed).
33
+ - The tool names from the spec also work as subcommands: `codebase_semantic_search`, `codebase_get_symbol_relations`, `codebase_get_optimized_context` (options `--query`, `--symbol_name --relation_direction`, `--file_path --focus_lines --padding_lines`).
34
+
35
+ ## Usage (Claude Code / MCP)
36
+
37
+ ```bash
38
+ claude mcp add local-indexer -- local-codebase-indexer --root /path/to/project serve
39
+ # without installing: claude mcp add local-indexer -- uvx local-codebase-indexer --root /path/to/project serve
40
+ ```
41
+
42
+ `serve` speaks JSON-RPC (MCP) over stdio and exposes five tools: `codebase_semantic_search`, `codebase_get_symbol_relations`, `codebase_get_optimized_context`, `codebase_get_data_access`, `codebase_index_status`.
43
+
44
+ ## Three-layer index
45
+
46
+ | Layer | Implementation |
47
+ |---|---|
48
+ | Syntactic | tree-sitter for C#, Python, JavaScript, TypeScript/TSX; regex for SQL (PROCEDURE / VIEW / FUNCTION / TABLE); other text files (VB6 `.frm`, `.config`, `.md`, ...) are split into windowed chunks |
49
+ | Topology | `using` / `import` resolved to file dependencies, inheritance (base lists) and type usage (`invocation`), stored in the `dependencies` table |
50
+ | Semantic | 384-dim chunk embeddings in `vss_chunks`; queries fuse FTS5 keyword, symbol-name and vector rankings with Reciprocal Rank Fusion, then expand to the dependency neighbours of the top 3 files |
51
+
52
+ Encodings: UTF-8 first, then Big5, then cp1252. Files over 5MB are skipped. Root and nested `.gitignore` files are respected, and `.git`, `bin`, `obj`, `node_modules` and similar directories are always skipped.
53
+
54
+ ## Differences from the spec
55
+
56
+ - **Vector storage**: `sqlite-vss` needs a native extension and is no longer maintained, so `vss_chunks` stores float32 BLOBs and cosine similarity is computed with numpy. No extension to install.
57
+ - **Embedding model**: the default is a built-in hashing embedder (identifier sub-words, bigrams, CJK character bigrams). It is fast and reproducible but **does not understand synonyms**. For real transformer embeddings, export `all-MiniLM-L6-v2` or `bge-small-en-v1.5` to ONNX, install `onnxruntime` and `tokenizers`, and set `INDEXER_ONNX_MODEL=<folder with model.onnx and tokenizer.json>` (the loading, padding, pooling and re-index logic is covered by a test with a tiny synthetic model; retrieval quality with a real model has not been measured, so run `python benchmarks/run_benchmark.py --compare benchmarks/baseline.json` with the variable set to check it; mean pooling suits MiniLM, bge models recommend CLS pooling). Switching embedders triggers a full re-index.
58
+ - **Call relations** for C# are resolved with limited type inference (using / namespaces, field and constructor-injected types, locals, interface to implementation), and every edge carries a confidence: `confirmed` (the receiver type is known), `probable` (reached through an interface or a single candidate) or `candidate` (name match only). There is no Roslyn: no overload resolution by argument type, no delegates / lambdas / extension methods, and call chains are followed one level. Inheritance edges come from the AST and are reliable.
59
+ - Extra schema additions: `symbols.qualified_name`, `chunk_metadata.symbol_id`, and the `raw_refs`, `chunks_fts` and `meta` tables.
60
+
61
+ ## Data access (SQL)
62
+
63
+ `data-access <table-or-procedure>` answers "what writes / reads / executes X". It is built from T-SQL (INSERT / UPDATE / DELETE / MERGE / TRUNCATE / SELECT INTO / FROM / JOIN / EXEC, with alias resolution; CTEs, temp tables and system objects excluded), from C# SQL strings (literals, `+`, interpolation, `string.Format`, consts, locals) passed to Dapper, `SqlCommand` or EF `FromSql`, from stored-procedure names used with `CommandType.StoredProcedure`, and from EF `ToTable` / `[Table]` mappings. A procedure's callers are indirect writers of the tables it writes (followed up to 4 hops). Each entry has a confidence; **dynamic SQL (`EXEC(@sql)`, `sp_executesql`, SQL built from unknown values) cannot be resolved and is listed separately as `uncertain`**, never mixed into the confirmed lists. Known gaps: `FROM a JOIN b ON ..., c` loses `c`, and a stored-procedure name passed to a non-database method is not seen.
64
+
65
+ Natural-language search routes questions such as "who modifies MES_ScrapRecord" or "哪些程式會寫入 MES_Lot" to this index first.
66
+
67
+ ## Query expansion
68
+
69
+ Queries are expanded with a small synonym dictionary (`SP` / `預存程序` / `stored procedure` / `usp`, table, lot, scrap, ...; `local_codebase_indexer/synonyms.py`). Add or disable groups per project in `.ai_context/synonyms.json`: `{"groups": [["wpnlot", "在製批"]], "disable": ["sp"]}`. This helps abbreviations and Chinese/English terms, not free paraphrase.
70
+
71
+ ## Index health
72
+
73
+ `status` (also the MCP tool `codebase_index_status`) reports whether the index can be trusted without refreshing it: `fresh`, `stale` (files changed or git HEAD moved since the last update), `degraded` (failed files or an inconsistent database) or `not_indexed`. A file that fails to parse is removed from the index, listed with its error, and retried on every update, so search never returns stale lines for it. `index --force` rebuilds everything.
74
+
75
+ ## Benchmark
76
+
77
+ `python benchmarks/run_benchmark.py` measures Recall@5, Recall@10 and MRR on fixed queries. See [`benchmarks/README.md`](benchmarks/README.md).
78
+
79
+ ## Tests
80
+
81
+ ```bash
82
+ python -m pytest -q
83
+ ```
@@ -0,0 +1,83 @@
1
+ # Local Codebase Indexer(本地代码索引器)
2
+
3
+ [English](README.md) | [繁體中文](README.zh-TW.md) | **简体中文**
4
+
5
+ 为 AI 编程助手(Claude Code 通过 MCP,GitHub Copilot / Codex 通过 CLI)打造的本地代码索引与上下文提供工具,让它们在大型遗留项目中用更少的 token 找到代码。索引全部存放在项目下的 `.ai_context/indexer.db`,不连接任何云服务。设计依据见 [`index.md`](index.md)。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ pip install local-codebase-indexer # Python 3.10+
11
+ # 或与其他包隔离安装:
12
+ pipx install local-codebase-indexer
13
+ # 可选:真正的嵌入模型(见下文)pip install "local-codebase-indexer[onnx]"
14
+ ```
15
+
16
+ 从源码:`pip install -e .`(在 clone 下 `bin/indexer` 仍可使用)。
17
+
18
+ ## 使用(CLI)
19
+
20
+ ```bash
21
+ local-codebase-indexer --root <项目路径> index # 建立 / 增量更新索引(--force 全部重建)
22
+ local-codebase-indexer search "database mapping for LotNo" --limit 5
23
+ local-codebase-indexer relations IExistOpenHandleService --direction both # upstream | downstream | both
24
+ local-codebase-indexer context Services/LotService.cs --lines 120 --padding 15 # 别名:slice
25
+ local-codebase-indexer data-access MES_Lot # 谁读 / 写 / 执行某数据表或存储过程;存储过程碰了哪些数据
26
+ local-codebase-indexer stats
27
+ local-codebase-indexer status # 索引是否新鲜、失败文件、git commit、一致性检查
28
+ ```
29
+
30
+ - 不指定 `--root` 时使用当前目录,也可用环境变量 `INDEXER_ROOT`。
31
+ - 加 `--json`(放在子命令前)输出 JSON。
32
+ - `search`、`relations`、`context` 执行前会自动做一次增量更新(先比较 mtime,mtime 变了才计算 md5)。
33
+ - 规格中的工具名称也可以直接作为子命令:`codebase_semantic_search`、`codebase_get_symbol_relations`、`codebase_get_optimized_context`(参数 `--query`、`--symbol_name --relation_direction`、`--file_path --focus_lines --padding_lines`)。
34
+
35
+ ## 使用(Claude Code / MCP)
36
+
37
+ ```bash
38
+ claude mcp add local-indexer -- local-codebase-indexer --root /path/to/project serve
39
+ # 不安装直接运行:claude mcp add local-indexer -- uvx local-codebase-indexer --root /path/to/project serve
40
+ ```
41
+
42
+ `serve` 通过 stdio 提供 JSON-RPC(MCP),暴露五个工具:`codebase_semantic_search`、`codebase_get_symbol_relations`、`codebase_get_optimized_context`、`codebase_get_data_access`、`codebase_index_status`。
43
+
44
+ ## 三层索引
45
+
46
+ | 层 | 实现 |
47
+ |---|---|
48
+ | Syntactic | tree-sitter 解析 C#、Python、JavaScript、TypeScript/TSX;SQL 用正则提取 PROCEDURE / VIEW / FUNCTION / TABLE;其余文本文件(VB6 `.frm`、`.config`、`.md` 等)切成窗口块 |
49
+ | Topology | `using` / `import` 解析为文件依赖;继承(base list);类型使用(`invocation`)。存放在 `dependencies` 表 |
50
+ | Semantic | 代码块嵌入 384 维,存入 `vss_chunks`;查询时用 FTS5 关键字、符号名称、向量三路做 Reciprocal Rank Fusion,再展开前 3 名文件的依赖邻居 |
51
+
52
+ 编码:先尝试 UTF-8,再尝试 Big5、cp1252。单个文件超过 5MB 不索引;遵守根目录与子目录的 `.gitignore`;固定跳过 `.git`、`bin`、`obj`、`node_modules` 等。
53
+
54
+ ## 与规格的差异
55
+
56
+ - **向量存储**:规格中的 `sqlite-vss` 需要原生扩展且已停止维护,这里 `vss_chunks` 改为存 float32 BLOB,用 numpy 暴力计算 cosine,不需要额外安装扩展。
57
+ - **嵌入模型**:默认是内置的 hashing 嵌入(标识符拆词、双词组、中文双字),快速、可复现,但**不理解同义词**。要使用真正的 transformer,把 `all-MiniLM-L6-v2` 或 `bge-small-en-v1.5` 导出为 ONNX,安装 `onnxruntime`、`tokenizers`,并设置 `INDEXER_ONNX_MODEL=<包含 model.onnx 与 tokenizer.json 的文件夹>`(加载、补齐、池化与重建索引的逻辑已用一个小型合成模型测试过;真实模型的检索质量尚未度量,设置好变量后请运行 `python benchmarks/run_benchmark.py --compare benchmarks/baseline.json` 验证;目前使用平均池化,适合 MiniLM,bge 系列建议使用 CLS 池化)。切换嵌入后会自动重建索引。
58
+ - **C# 调用关系**以有限度的类型推断解析(using / namespace、字段与构造函数注入的类型、局部变量、接口对应实现),每条关系都标置信等级:`confirmed`(接收者类型已知)、`probable`(经由接口或唯一候选)、`candidate`(仅名称相符)。没有 Roslyn,所以不做按参数类型的重载解析、不处理委托 / lambda / 扩展方法,调用链只追一层。继承关系来自 AST,可靠。
59
+ - 额外增加了 `symbols.qualified_name`、`chunk_metadata.symbol_id`、`raw_refs`、`chunks_fts` 与 `meta` 表。
60
+
61
+ ## 数据访问(SQL)
62
+
63
+ `data-access <数据表或存储过程>` 回答“谁写入 / 读取 / 执行 X”。数据来源:T-SQL(INSERT / UPDATE / DELETE / MERGE / TRUNCATE / SELECT INTO / FROM / JOIN / EXEC,含别名解析,排除 CTE、临时表、系统对象)、C# 的 SQL 字符串(字面值、`+`、字符串插值、`string.Format`、常量、局部变量)经 Dapper、`SqlCommand` 或 EF `FromSql` 发出、配合 `CommandType.StoredProcedure` 的存储过程名称,以及 EF 的 `ToTable` / `[Table]` 映射。调用某存储过程的代码视为该过程所写数据表的间接写入者(最多追 4 层)。每条都有置信等级;**动态 SQL(`EXEC(@sql)`、`sp_executesql`、由未知值组成的 SQL)无法解析,会单独列为 `uncertain`**,不会混进确定的清单。已知缺口:`FROM a JOIN b ON ..., c` 会漏掉 `c`;把存储过程名称传给非数据库方法时看不到。
64
+
65
+ 自然语言搜索遇到“谁修改 MES_ScrapRecord”“哪些程序会写入 MES_Lot”这类问题,会先走这个索引。
66
+
67
+ ## 查询扩展
68
+
69
+ 查询会用小型同义词字典扩展(`SP` / `预存程序` / `stored procedure` / `usp`、数据表、批号、报废等;见 `local_codebase_indexer/synonyms.py`)。可在 `.ai_context/synonyms.json` 为项目新增或停用分组:`{"groups": [["wpnlot", "在制批"]], "disable": ["sp"]}`。这对缩写与中英对照有帮助,对自由改写的同义说法没用。
70
+
71
+ ## 索引健康状态
72
+
73
+ `status`(也是 MCP 工具 `codebase_index_status`)不更新索引,只报告索引是否可信:`fresh`(新鲜)、`stale`(文件有变更或 git HEAD 已移动)、`degraded`(有解析失败的文件或数据库不一致)、`not_indexed`(尚未建立)。解析失败的文件会从索引移除、连同错误原因列出,并在每次更新时重试,所以搜索不会返回它的过期内容。`index --force` 可全部重建。
74
+
75
+ ## 基准测试
76
+
77
+ `python benchmarks/run_benchmark.py` 用固定问题度量 Recall@5、Recall@10 与 MRR,详见 [`benchmarks/README.md`](benchmarks/README.md)(英文)。
78
+
79
+ ## 测试
80
+
81
+ ```bash
82
+ python -m pytest -q
83
+ ```
@@ -0,0 +1,83 @@
1
+ # Local Codebase Indexer(本機程式碼索引器)
2
+
3
+ [English](README.md) | **繁體中文** | [简体中文](README.zh-CN.md)
4
+
5
+ 為 AI 程式助理(Claude Code 走 MCP,GitHub Copilot / Codex 走 CLI)打造的本機程式碼索引與 context 提供工具,讓它們在大型舊專案中用更少的 token 找到程式碼。索引全部存在專案下的 `.ai_context/indexer.db`,不連任何雲端服務。設計依據見 [`index.md`](index.md)。
6
+
7
+ ## 安裝
8
+
9
+ ```bash
10
+ pip install local-codebase-indexer # Python 3.10+
11
+ # 或與其他套件隔離安裝:
12
+ pipx install local-codebase-indexer
13
+ # 選用:真正的嵌入模型(見下文)pip install "local-codebase-indexer[onnx]"
14
+ ```
15
+
16
+ 從原始碼:`pip install -e .`(在 clone 下 `bin/indexer` 仍可使用)。
17
+
18
+ ## 使用(CLI)
19
+
20
+ ```bash
21
+ local-codebase-indexer --root <專案路徑> index # 建立 / 增量更新索引(--force 全部重建)
22
+ local-codebase-indexer search "database mapping for LotNo" --limit 5
23
+ local-codebase-indexer relations IExistOpenHandleService --direction both # upstream | downstream | both
24
+ local-codebase-indexer context Services/LotService.cs --lines 120 --padding 15 # 別名:slice
25
+ local-codebase-indexer data-access MES_Lot # 誰讀 / 寫 / 執行某資料表或預存程序;預存程序碰了哪些資料
26
+ local-codebase-indexer stats
27
+ local-codebase-indexer status # 索引是否新鮮、失敗檔案、git commit、一致性檢查
28
+ ```
29
+
30
+ - 不給 `--root` 時使用目前目錄,也可用環境變數 `INDEXER_ROOT`。
31
+ - 加 `--json`(放在子命令前)輸出 JSON。
32
+ - `search`、`relations`、`context` 執行前會自動做一次增量更新(先比 mtime,mtime 變了才算 md5)。
33
+ - 規格中的工具名稱也可直接當子命令:`codebase_semantic_search`、`codebase_get_symbol_relations`、`codebase_get_optimized_context`(參數 `--query`、`--symbol_name --relation_direction`、`--file_path --focus_lines --padding_lines`)。
34
+
35
+ ## 使用(Claude Code / MCP)
36
+
37
+ ```bash
38
+ claude mcp add local-indexer -- local-codebase-indexer --root /path/to/project serve
39
+ # 不安裝直接跑:claude mcp add local-indexer -- uvx local-codebase-indexer --root /path/to/project serve
40
+ ```
41
+
42
+ `serve` 以 stdio 提供 JSON-RPC(MCP),暴露五個工具:`codebase_semantic_search`、`codebase_get_symbol_relations`、`codebase_get_optimized_context`、`codebase_get_data_access`、`codebase_index_status`。
43
+
44
+ ## 三層索引
45
+
46
+ | 層 | 實作 |
47
+ |---|---|
48
+ | Syntactic | tree-sitter 解析 C#、Python、JavaScript、TypeScript/TSX;SQL 用 regex 抽 PROCEDURE / VIEW / FUNCTION / TABLE;其餘文字檔(VB6 `.frm`、`.config`、`.md` 等)切成視窗區塊 |
49
+ | Topology | `using` / `import` 解析成檔案相依;繼承(base list);型別使用(`invocation`)。存在 `dependencies` 表 |
50
+ | Semantic | 區塊嵌入 384 維,存 `vss_chunks`;查詢時以 FTS5 關鍵字、符號名稱、向量三路做 Reciprocal Rank Fusion,再展開前 3 名檔案的相依鄰居 |
51
+
52
+ 編碼:先試 UTF-8,再試 Big5、cp1252。單檔超過 5MB 不索引;遵守根目錄與子目錄的 `.gitignore`;固定略過 `.git`、`bin`、`obj`、`node_modules` 等。
53
+
54
+ ## 與規格的差異
55
+
56
+ - **向量儲存**:規格的 `sqlite-vss` 需要原生擴充且已停止維護,這裡 `vss_chunks` 改存 float32 BLOB,用 numpy 暴力計算 cosine,不需要額外安裝擴充。
57
+ - **嵌入模型**:預設是內建的 hashing 嵌入(識別字拆詞、雙詞組、中文雙字),快速、可重現,但**不理解同義詞**。要用真正的 transformer,匯出 `all-MiniLM-L6-v2` 或 `bge-small-en-v1.5` 為 ONNX,裝 `onnxruntime`、`tokenizers`,並設 `INDEXER_ONNX_MODEL=<含 model.onnx 與 tokenizer.json 的資料夾>`(載入、補齊、池化與重建索引的邏輯已用一個小型合成模型測試過;真實模型的檢索品質尚未量測,設好變數後請執行 `python benchmarks/run_benchmark.py --compare benchmarks/baseline.json` 驗證;目前用平均池化,適合 MiniLM,bge 系列建議用 CLS 池化)。切換嵌入後會自動重建索引。
58
+ - **C# 呼叫關係**以有限度的型別推斷解析(using / namespace、欄位與建構式注入的型別、區域變數、介面對應實作),每條關係都標信心等級:`confirmed`(接收者型別已知)、`probable`(經由介面或唯一候選)、`candidate`(僅名稱相符)。沒有 Roslyn,所以不做依引數型別的多載解析、不處理委派 / lambda / 擴充方法,呼叫鏈只追一層。繼承關係來自 AST,可靠。
59
+ - 額外加了 `symbols.qualified_name`、`chunk_metadata.symbol_id`、`raw_refs`、`chunks_fts` 與 `meta` 表。
60
+
61
+ ## 資料存取(SQL)
62
+
63
+ `data-access <資料表或預存程序>` 回答「誰寫入 / 讀取 / 執行 X」。資料來源:T-SQL(INSERT / UPDATE / DELETE / MERGE / TRUNCATE / SELECT INTO / FROM / JOIN / EXEC,含別名解析,排除 CTE、暫存表、系統物件)、C# 的 SQL 字串(字面值、`+`、字串內插、`string.Format`、常數、區域變數)經 Dapper、`SqlCommand` 或 EF `FromSql` 送出、搭配 `CommandType.StoredProcedure` 的 SP 名稱,以及 EF 的 `ToTable` / `[Table]` 對應。呼叫某 SP 的程式視為該 SP 所寫資料表的間接寫入者(最多追 4 層)。每筆都有信心等級;**動態 SQL(`EXEC(@sql)`、`sp_executesql`、由未知值組成的 SQL)無法解析,會獨立列為 `uncertain`**,不會混進確定的清單。已知缺口:`FROM a JOIN b ON ..., c` 會漏掉 `c`;把 SP 名稱傳給非資料庫方法時看不到。
64
+
65
+ 自然語言搜尋遇到「誰修改 MES_ScrapRecord」「哪些程式會寫入 MES_Lot」這類問題,會先走這個索引。
66
+
67
+ ## 查詢擴展
68
+
69
+ 查詢會用小型同義詞字典擴展(`SP` / `預存程序` / `stored procedure` / `usp`、資料表、批號、報廢等;見 `local_codebase_indexer/synonyms.py`)。可在 `.ai_context/synonyms.json` 為專案新增或停用群組:`{"groups": [["wpnlot", "在製批"]], "disable": ["sp"]}`。這對縮寫與中英對照有幫助,對自由改寫的同義說法沒用。
70
+
71
+ ## 索引健康狀態
72
+
73
+ `status`(也是 MCP 工具 `codebase_index_status`)不更新索引,只回報索引是否可信:`fresh`(新鮮)、`stale`(檔案有變更或 git HEAD 已移動)、`degraded`(有解析失敗的檔案或資料庫不一致)、`not_indexed`(尚未建立)。解析失敗的檔案會從索引移除、連同錯誤原因列出,並在每次更新時重試,所以搜尋不會回傳它的過期內容。`index --force` 可全部重建。
74
+
75
+ ## 基準測試
76
+
77
+ `python benchmarks/run_benchmark.py` 以固定問題量測 Recall@5、Recall@10 與 MRR,詳見 [`benchmarks/README.md`](benchmarks/README.md)(英文)。
78
+
79
+ ## 測試
80
+
81
+ ```bash
82
+ python -m pytest -q
83
+ ```
@@ -0,0 +1,30 @@
1
+ # TODO
2
+
3
+ Priorities come from the benchmark (`benchmarks/run_benchmark.py`, baseline in `benchmarks/baseline.json`) and the measurements below, not from guesses.
4
+
5
+ ## Next
6
+
7
+ 1. **Check a real embedding model on your own machine** (this environment cannot reach Hugging Face, so the ONNX path is only tested with a tiny generated model). Export a model such as `all-MiniLM-L6-v2` (mean pooling) or `bge-small-en-v1.5` (`INDEXER_ONNX_POOLING=cls`, `INDEXER_ONNX_QUERY_PREFIX="Represent this sentence for searching relevant passages: "`), set `INDEXER_ONNX_MODEL`, and run `python benchmarks/run_benchmark.py --compare benchmarks/baseline.json`.
8
+ Evidence: `synonym` Recall@5 is only 0.30 (hashing embedder plus the dictionary, which cannot cover free paraphrase). Whether a real model fixes this is not measured.
9
+ 2. **Resolve `FROM a JOIN b ON ..., c`** (a comma list after a JOIN loses `c`), non-sink SQL proc-name literals (`Run("usp_X")`), and EF query tracing (only the table mapping is recorded now).
10
+ 3. **C# call graph gaps**: overload resolution by argument type, delegates / lambdas / extension methods, call chains longer than one level. Without Roslyn these stay approximate; edges carry `confirmed` / `probable` / `candidate`.
11
+
12
+ ## Deferred (not worth doing yet)
13
+
14
+ | Item | Why deferred | Revisit when |
15
+ |---|---|---|
16
+ | ANN index | Exact search is not the bottleneck. Measured (Python stdlib copies, linear growth): 17k chunks cold CLI search 0.35 s / warm 0.13 s / index 10 s; 52k chunks 0.75 s / 0.36 s / 28 s; 104k chunks 1.09 s / 0.73 s / 54 s, 372 MB RSS, 729 MB database. At 104k chunks the cosine product plus top-k takes about 12 ms; loading the vectors out of SQLite (fetch 0.31 s, join 0.12 s) is about half of a warm query | Exact cosine itself becomes slow, which is far beyond 1M chunks |
17
+ | Vector matrix cache | Cheap and measurable: it removes about half of a warm query at 104k chunks (about 0.8 s -> 0.3 s). Not needed below ~50k chunks | A real project passes ~50k chunks. Keep the matrix in the MCP server process, and/or store it as a memory-mapped `.npy` next to the database so the CLI benefits too (invalidate on any index change) |
18
+ | `codebase_trace_execution` | Needs reliable call / data-flow relations; today's usage edges are name matches | Call graph gaps (item 3) are narrowed; today edges carry a confidence level |
19
+ | `codebase_impact_analysis` | Same dependency; must separate confirmed from guessed edges | Call graph gaps (item 3) are narrowed; today edges carry a confidence level |
20
+ | `codebase_architecture_overview` | Low value for the intended use cases | A concrete need appears |
21
+ | `codebase_find_references` (upgrade) | `relations` already returns name-matched references | Done in part: `relations` already separates confirmed / probable / candidate callers |
22
+
23
+ ## Done
24
+
25
+ - SQL / data-access relations: `data_access` table and tool (`data-access` CLI, `codebase_get_data_access` MCP); T-SQL read / write / exec, C# SQL strings and Dapper / SqlCommand / EF sinks, EF table mappings, indirect writers through procedures, dynamic SQL reported as `uncertain`; search routes "who writes / reads / calls X" to it. Benchmark `sql_dataflow` Recall@5 0.72 -> 1.00, new `data_access` queries 0.67 -> 1.00
26
+ - C# symbol-level calls: using / field / constructor-injection / local type inference, interface dispatch, confidence levels. `relations Save` no longer shares one reference list across four unrelated methods
27
+ - Domain-term query expansion (`local_codebase_indexer/synonyms.py`, extendable with `.ai_context/synonyms.json`); `abbreviation` Recall@5 0.67 -> 1.00, `cross_lingual` 0.50 -> 1.00 (small, author-written sets: optimistic). ONNX pooling / query-prefix options
28
+ - Index status tool, failure log (failed files are removed from the index and retried), git commit metadata, consistency checks
29
+ - Search quality benchmark with a lint for leaky synonym queries
30
+ - Chinese text indexed as character bigrams in full-text search
@@ -0,0 +1,35 @@
1
+ # Search quality benchmark
2
+
3
+ Fixed queries with known answers, so a change to chunking, embeddings or ranking can be judged by numbers.
4
+
5
+ ```bash
6
+ python benchmarks/run_benchmark.py # all suites
7
+ python benchmarks/run_benchmark.py --misses # also list queries whose answer is not in the top 5
8
+ python benchmarks/run_benchmark.py --compare benchmarks/baseline.json # show deltas against the saved baseline
9
+ python benchmarks/run_benchmark.py --save benchmarks/baseline.json # replace the baseline after an accepted change
10
+ ```
11
+
12
+ ## Suites
13
+
14
+ | Suite | Corpus | Purpose |
15
+ |---|---|---|
16
+ | `synthetic` | `corpus/`: 24 small C#, SQL, VB6, TypeScript, Python and config files modelled on an MES code base | Controlled vocabulary tests: exact names, synonyms, abbreviations, Chinese, same-name methods, cross-file, SQL data flow |
17
+ | `synthetic-noisy` | the same corpus buried among ~2,600 unrelated Python chunks | The same queries, but the answers must compete with distractors, closer to a real project |
18
+ | `stdlib` | email, json, http, asyncio, unittest from the Python standard library | Real code and queries not written around the corpus (depends on the Python version) |
19
+
20
+ Expected answers are `file` plus an optional `symbol` suffix. A result is relevant when both match.
21
+
22
+ - **Recall@k** = expected answers found in the top k / expected answers.
23
+ - **MRR** = mean of 1 / rank of the first relevant result.
24
+ - **tokens returned / whole files** estimates (characters / 4) what the default 5 results cost compared with reading the files they point at. It is only meaningful on the larger corpora; the synthetic files are tiny.
25
+
26
+ ## Caveats
27
+
28
+ - The synthetic corpus, its queries and the synonym dictionary were written by the same author (the `data_access` queries were written before the routing existed, to limit tuning), so absolute numbers are optimistic. `synonym` (free paraphrase) is still 0.30: a dictionary cannot fix it.
29
+ - The synthetic corpus and its queries were written by the same author, so absolute numbers are optimistic. Use them to compare versions, not to claim a quality level.
30
+ - `synonym` and `cross_lingual` queries must share no content word with their answers. The runner lints this (`LINT:` lines) and a test fails if a query leaks.
31
+ - Some `stdlib` answers are debatable (for example `email.headerregistry.Address` is also a reasonable answer for "format an address"), so treat that suite as a relative measure.
32
+
33
+ ## History
34
+
35
+ - Chinese queries in the noisy corpus: Recall@5 0.50 -> 1.00 after Chinese runs were indexed as character bigrams (SQLite FTS5 keeps a whole run of Chinese characters as one token).