repoatlas-cli 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nishant
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,297 @@
1
+ Metadata-Version: 2.4
2
+ Name: repoatlas-cli
3
+ Version: 0.2.0
4
+ Summary: Ask natural-language questions about any code repository — powered by local LLMs and ChromaDB. Zero server setup.
5
+ License-Expression: MIT
6
+ Project-URL: Repository, https://github.com/yourusername/repolens
7
+ Keywords: rag,llm,code-search,ollama,chromadb,cli
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Console
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Topic :: Software Development :: Libraries
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: typer>=0.12
19
+ Requires-Dist: rich>=13
20
+ Requires-Dist: httpx>=0.27
21
+ Requires-Dist: chromadb>=0.6
22
+ Requires-Dist: pyyaml>=6
23
+ Provides-Extra: openai
24
+ Requires-Dist: openai>=1.30; extra == "openai"
25
+ Provides-Extra: anthropic
26
+ Requires-Dist: anthropic>=0.28; extra == "anthropic"
27
+ Provides-Extra: groq
28
+ Requires-Dist: groq>=0.9; extra == "groq"
29
+ Provides-Extra: all
30
+ Requires-Dist: openai>=1.30; extra == "all"
31
+ Requires-Dist: anthropic>=0.28; extra == "all"
32
+ Requires-Dist: groq>=0.9; extra == "all"
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest>=8; extra == "dev"
35
+ Requires-Dist: pytest-cov; extra == "dev"
36
+ Requires-Dist: ruff; extra == "dev"
37
+ Requires-Dist: mypy; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # RepoAtlas
41
+
42
+ > Ask natural-language questions about any code repository — powered by local LLMs and ChromaDB. Runs fully offline. Zero server setup.
43
+
44
+ ```
45
+ repoatlas init
46
+ repoatlas index /path/to/myproject
47
+ repoatlas ask "how does authentication work here?"
48
+ ```
49
+
50
+ ---
51
+
52
+ ## What it is
53
+
54
+ RepoAtlas is a CLI tool that turns any code repository into a searchable knowledge base. Point it at a repo, index it once, then ask questions in plain English and get answers grounded in the actual code — not generic guesses.
55
+
56
+ It combines **AST-based chunking**, **vector embeddings**, and a **local LLM** into a standard RAG (Retrieval-Augmented Generation) pipeline — running entirely on your own machine, with no data leaving your network.
57
+
58
+ **No Postgres. No server. No connection strings.** ChromaDB stores everything in a local directory (`~/.repoatlas/chroma_db`) that just works.
59
+
60
+ ---
61
+
62
+ ## Why local-first?
63
+
64
+ - **Privacy / compliance** — banking, defense, legal, and other regulated environments forbid sending proprietary code to cloud AI APIs. RepoAtlas works with zero network access by default.
65
+ - **Air-gapped environments** — cloud-based agents don't work here at all.
66
+ - **No API costs** — the default stack (Ollama + `nomic-embed-text` + `qwen2.5-coder:3b`) is entirely free.
67
+ - Cloud providers (OpenAI, Anthropic, Groq) are available as opt-in backends for users with weaker hardware.
68
+
69
+ ---
70
+
71
+ ## How it works
72
+
73
+ ```
74
+ Repo files
75
+
76
+
77
+ [Chunker] AST-based for .py (top-level functions & classes)
78
+ Line-window (50 lines, 10-line overlap) for all other files
79
+
80
+
81
+ [Embedder] nomic-embed-text via Ollama → 768-dim vectors
82
+
83
+
84
+ [ChromaDB] Local embedded vector store — no server, just a directory
85
+
86
+ ▼ (at query time)
87
+ [Retriever] Embeds the question, cosine-similarity search → top-k chunks
88
+
89
+
90
+ [LLM] Chunks + question → prompt → grounded answer
91
+ ```
92
+
93
+ ---
94
+
95
+ ## Requirements
96
+
97
+ - Python 3.11+
98
+ - [Ollama](https://ollama.com/) (for local mode)
99
+
100
+ That's it. ChromaDB is installed automatically as a Python dependency — no server setup needed.
101
+
102
+ ---
103
+
104
+ ## Installation
105
+
106
+ ```bash
107
+ pip install repoatlas
108
+ ```
109
+
110
+ For cloud provider support (optional):
111
+ ```bash
112
+ pip install "repoatlas[openai]"
113
+ pip install "repoatlas[anthropic]"
114
+ pip install "repoatlas[groq]"
115
+ pip install "repoatlas[all]" # all cloud providers
116
+ ```
117
+
118
+ ---
119
+
120
+ ## Quickstart
121
+
122
+ ### 1. Run setup (first time only)
123
+
124
+ ```bash
125
+ repoatlas init
126
+ ```
127
+
128
+ This will:
129
+ - Check that Ollama is installed and running
130
+ - Pull the required models (`nomic-embed-text`, `qwen2.5-coder:3b`)
131
+ - Confirm the ChromaDB storage path
132
+ - Write `~/.repoatlas/config.yaml` so you never have to configure again
133
+
134
+ ### 2. Index a repository
135
+
136
+ ```bash
137
+ repoatlas index /path/to/myproject
138
+ ```
139
+
140
+ ### 3. Ask questions
141
+
142
+ ```bash
143
+ repoatlas ask "how does authentication work?"
144
+ repoatlas ask "where is the database connection handled?"
145
+ repoatlas ask "how do I add a new API endpoint?"
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Usage
151
+
152
+ ### `repoatlas init`
153
+
154
+ Interactive first-time setup. Checks Ollama, pulls models, writes config.
155
+
156
+ ```bash
157
+ repoatlas init [--chroma-path PATH] [--chat-model MODEL] [--embed-model MODEL]
158
+ ```
159
+
160
+ ### `repoatlas index`
161
+
162
+ ```bash
163
+ repoatlas index <repo_path> [OPTIONS]
164
+ ```
165
+
166
+ | Option | Default | Description |
167
+ |---|---|---|
168
+ | `--reset` | off | Wipe entire ChromaDB collection before indexing |
169
+ | `--chroma-path` | `~/.repoatlas/chroma_db` | ChromaDB storage directory |
170
+ | `--embed-model` | `nomic-embed-text` | Ollama embedding model |
171
+
172
+ ### `repoatlas ask`
173
+
174
+ ```bash
175
+ repoatlas ask <question> [OPTIONS]
176
+ ```
177
+
178
+ | Option | Default | Description |
179
+ |---|---|---|
180
+ | `--repo` | (all repos) | Restrict retrieval to a specific repo path |
181
+ | `--top-k` | 5 | Number of chunks to retrieve (1–20) |
182
+ | `--provider` | `ollama` | `ollama` \| `openai` \| `anthropic` \| `groq` |
183
+ | `--model` | provider default | Chat model override |
184
+ | `--chroma-path` | `~/.repoatlas/chroma_db` | ChromaDB storage directory |
185
+ | `--no-sources` | off | Hide source citations |
186
+
187
+ ---
188
+
189
+ ## Using cloud providers
190
+
191
+ ```bash
192
+ # OpenAI
193
+ export OPENAI_API_KEY=sk-...
194
+ repoatlas ask "explain the auth flow" --provider openai --model gpt-4o
195
+
196
+ # Anthropic
197
+ export ANTHROPIC_API_KEY=sk-ant-...
198
+ repoatlas ask "explain the auth flow" --provider anthropic
199
+
200
+ # Groq (fast inference, free tier available)
201
+ export GROQ_API_KEY=gsk_...
202
+ repoatlas ask "explain the auth flow" --provider groq
203
+ ```
204
+
205
+ ---
206
+
207
+ ## Configuration
208
+
209
+ ### Environment variables
210
+
211
+ | Variable | Description |
212
+ |---|---|
213
+ | `REPOATLAS_CHROMA_PATH` | ChromaDB storage path (default: `~/.repoatlas/chroma_db`) |
214
+ | `REPOATLAS_PROVIDER` | Default LLM provider (`ollama`) |
215
+ | `REPOATLAS_MODEL` | Default chat model |
216
+ | `REPOATLAS_EMBED_MODEL` | Embedding model (default: `nomic-embed-text`) |
217
+ | `OLLAMA_BASE_URL` | Ollama server URL (default: `http://localhost:11434`) |
218
+ | `OPENAI_API_KEY` | OpenAI API key |
219
+ | `ANTHROPIC_API_KEY` | Anthropic API key |
220
+ | `GROQ_API_KEY` | Groq API key |
221
+
222
+ ### Config file (`~/.repoatlas/config.yaml`)
223
+
224
+ After running `repoatlas init`, settings are persisted here. Environment variables override the config file.
225
+
226
+ ```yaml
227
+ chroma_path: ~/.repoatlas/chroma_db
228
+ provider: ollama
229
+ chat_model: qwen2.5-coder:3b
230
+ embed_model: nomic-embed-text
231
+ ollama_base_url: http://localhost:11434
232
+ ```
233
+
234
+ ---
235
+
236
+ ## Multiple repositories
237
+
238
+ RepoAtlas can hold multiple repos in the same ChromaDB — use `--repo` when querying to restrict to one:
239
+
240
+ ```bash
241
+ repoatlas index /path/to/project-a
242
+ repoatlas index /path/to/project-b
243
+
244
+ repoatlas ask "how does auth work?" --repo /path/to/project-a
245
+ repoatlas ask "how does auth work?" --repo /path/to/project-b
246
+ ```
247
+
248
+ ---
249
+
250
+ ## Project structure
251
+
252
+ ```
253
+ RepoAtlas/
254
+ ├── db/
255
+ │ └── chroma.py — ChromaDB client + collection helpers
256
+ ├── indexer/
257
+ │ ├── chunker.py — AST chunker (Python) + line-window fallback (all files)
258
+ │ ├── embedder.py — Ollama /api/embeddings wrapper
259
+ │ └── ingestion.py — Repo walker + indexing pipeline
260
+ ├── api/
261
+ │ └── retriever.py — ChromaDB cosine-similarity retrieval
262
+ ├── app/
263
+ │ ├── providers.py — Pluggable LLM backends (Ollama / OpenAI / Anthropic / Groq)
264
+ │ └── rag.py — RAG orchestration (retrieve → prompt → generate)
265
+ ├── cli/
266
+ │ └── main.py — Typer CLI (init, index, ask)
267
+ └── tests/
268
+ ├── test_chunker.py — Unit tests for chunking logic
269
+ └── test_retriever.py — Integration tests for retrieval
270
+ ```
271
+
272
+ ---
273
+
274
+ ## Running tests
275
+
276
+ ```bash
277
+ # Unit tests (no Ollama required)
278
+ pytest tests/test_chunker.py -v
279
+
280
+ # Integration tests (requires Ollama running)
281
+ pytest tests/ -v
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Roadmap
287
+
288
+ - [ ] Tree-sitter chunking for JS / Go / Rust / Java
289
+ - [ ] `repoatlas search` — raw chunk retrieval without LLM
290
+ - [ ] `repoatlas watch` — incremental re-indexing on file change
291
+ - [ ] Web UI
292
+
293
+ ---
294
+
295
+ ## License
296
+
297
+ MIT — see [LICENSE](LICENSE)
@@ -0,0 +1,258 @@
1
+ # RepoAtlas
2
+
3
+ > Ask natural-language questions about any code repository — powered by local LLMs and ChromaDB. Runs fully offline. Zero server setup.
4
+
5
+ ```
6
+ repoatlas init
7
+ repoatlas index /path/to/myproject
8
+ repoatlas ask "how does authentication work here?"
9
+ ```
10
+
11
+ ---
12
+
13
+ ## What it is
14
+
15
+ RepoAtlas is a CLI tool that turns any code repository into a searchable knowledge base. Point it at a repo, index it once, then ask questions in plain English and get answers grounded in the actual code — not generic guesses.
16
+
17
+ It combines **AST-based chunking**, **vector embeddings**, and a **local LLM** into a standard RAG (Retrieval-Augmented Generation) pipeline — running entirely on your own machine, with no data leaving your network.
18
+
19
+ **No Postgres. No server. No connection strings.** ChromaDB stores everything in a local directory (`~/.repoatlas/chroma_db`) that just works.
20
+
21
+ ---
22
+
23
+ ## Why local-first?
24
+
25
+ - **Privacy / compliance** — banking, defense, legal, and other regulated environments forbid sending proprietary code to cloud AI APIs. RepoAtlas works with zero network access by default.
26
+ - **Air-gapped environments** — cloud-based agents don't work here at all.
27
+ - **No API costs** — the default stack (Ollama + `nomic-embed-text` + `qwen2.5-coder:3b`) is entirely free.
28
+ - Cloud providers (OpenAI, Anthropic, Groq) are available as opt-in backends for users with weaker hardware.
29
+
30
+ ---
31
+
32
+ ## How it works
33
+
34
+ ```
35
+ Repo files
36
+
37
+
38
+ [Chunker] AST-based for .py (top-level functions & classes)
39
+ Line-window (50 lines, 10-line overlap) for all other files
40
+
41
+
42
+ [Embedder] nomic-embed-text via Ollama → 768-dim vectors
43
+
44
+
45
+ [ChromaDB] Local embedded vector store — no server, just a directory
46
+
47
+ ▼ (at query time)
48
+ [Retriever] Embeds the question, cosine-similarity search → top-k chunks
49
+
50
+
51
+ [LLM] Chunks + question → prompt → grounded answer
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Requirements
57
+
58
+ - Python 3.11+
59
+ - [Ollama](https://ollama.com/) (for local mode)
60
+
61
+ That's it. ChromaDB is installed automatically as a Python dependency — no server setup needed.
62
+
63
+ ---
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pip install repoatlas
69
+ ```
70
+
71
+ For cloud provider support (optional):
72
+ ```bash
73
+ pip install "repoatlas[openai]"
74
+ pip install "repoatlas[anthropic]"
75
+ pip install "repoatlas[groq]"
76
+ pip install "repoatlas[all]" # all cloud providers
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Quickstart
82
+
83
+ ### 1. Run setup (first time only)
84
+
85
+ ```bash
86
+ repoatlas init
87
+ ```
88
+
89
+ This will:
90
+ - Check that Ollama is installed and running
91
+ - Pull the required models (`nomic-embed-text`, `qwen2.5-coder:3b`)
92
+ - Confirm the ChromaDB storage path
93
+ - Write `~/.repoatlas/config.yaml` so you never have to configure again
94
+
95
+ ### 2. Index a repository
96
+
97
+ ```bash
98
+ repoatlas index /path/to/myproject
99
+ ```
100
+
101
+ ### 3. Ask questions
102
+
103
+ ```bash
104
+ repoatlas ask "how does authentication work?"
105
+ repoatlas ask "where is the database connection handled?"
106
+ repoatlas ask "how do I add a new API endpoint?"
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Usage
112
+
113
+ ### `repoatlas init`
114
+
115
+ Interactive first-time setup. Checks Ollama, pulls models, writes config.
116
+
117
+ ```bash
118
+ repoatlas init [--chroma-path PATH] [--chat-model MODEL] [--embed-model MODEL]
119
+ ```
120
+
121
+ ### `repoatlas index`
122
+
123
+ ```bash
124
+ repoatlas index <repo_path> [OPTIONS]
125
+ ```
126
+
127
+ | Option | Default | Description |
128
+ |---|---|---|
129
+ | `--reset` | off | Wipe entire ChromaDB collection before indexing |
130
+ | `--chroma-path` | `~/.repoatlas/chroma_db` | ChromaDB storage directory |
131
+ | `--embed-model` | `nomic-embed-text` | Ollama embedding model |
132
+
133
+ ### `repoatlas ask`
134
+
135
+ ```bash
136
+ repoatlas ask <question> [OPTIONS]
137
+ ```
138
+
139
+ | Option | Default | Description |
140
+ |---|---|---|
141
+ | `--repo` | (all repos) | Restrict retrieval to a specific repo path |
142
+ | `--top-k` | 5 | Number of chunks to retrieve (1–20) |
143
+ | `--provider` | `ollama` | `ollama` \| `openai` \| `anthropic` \| `groq` |
144
+ | `--model` | provider default | Chat model override |
145
+ | `--chroma-path` | `~/.repoatlas/chroma_db` | ChromaDB storage directory |
146
+ | `--no-sources` | off | Hide source citations |
147
+
148
+ ---
149
+
150
+ ## Using cloud providers
151
+
152
+ ```bash
153
+ # OpenAI
154
+ export OPENAI_API_KEY=sk-...
155
+ repoatlas ask "explain the auth flow" --provider openai --model gpt-4o
156
+
157
+ # Anthropic
158
+ export ANTHROPIC_API_KEY=sk-ant-...
159
+ repoatlas ask "explain the auth flow" --provider anthropic
160
+
161
+ # Groq (fast inference, free tier available)
162
+ export GROQ_API_KEY=gsk_...
163
+ repoatlas ask "explain the auth flow" --provider groq
164
+ ```
165
+
166
+ ---
167
+
168
+ ## Configuration
169
+
170
+ ### Environment variables
171
+
172
+ | Variable | Description |
173
+ |---|---|
174
+ | `REPOATLAS_CHROMA_PATH` | ChromaDB storage path (default: `~/.repoatlas/chroma_db`) |
175
+ | `REPOATLAS_PROVIDER` | Default LLM provider (`ollama`) |
176
+ | `REPOATLAS_MODEL` | Default chat model |
177
+ | `REPOATLAS_EMBED_MODEL` | Embedding model (default: `nomic-embed-text`) |
178
+ | `OLLAMA_BASE_URL` | Ollama server URL (default: `http://localhost:11434`) |
179
+ | `OPENAI_API_KEY` | OpenAI API key |
180
+ | `ANTHROPIC_API_KEY` | Anthropic API key |
181
+ | `GROQ_API_KEY` | Groq API key |
182
+
183
+ ### Config file (`~/.repoatlas/config.yaml`)
184
+
185
+ After running `repoatlas init`, settings are persisted here. Environment variables override the config file.
186
+
187
+ ```yaml
188
+ chroma_path: ~/.repoatlas/chroma_db
189
+ provider: ollama
190
+ chat_model: qwen2.5-coder:3b
191
+ embed_model: nomic-embed-text
192
+ ollama_base_url: http://localhost:11434
193
+ ```
194
+
195
+ ---
196
+
197
+ ## Multiple repositories
198
+
199
+ RepoAtlas can hold multiple repos in the same ChromaDB — use `--repo` when querying to restrict to one:
200
+
201
+ ```bash
202
+ repoatlas index /path/to/project-a
203
+ repoatlas index /path/to/project-b
204
+
205
+ repoatlas ask "how does auth work?" --repo /path/to/project-a
206
+ repoatlas ask "how does auth work?" --repo /path/to/project-b
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Project structure
212
+
213
+ ```
214
+ RepoAtlas/
215
+ ├── db/
216
+ │ └── chroma.py — ChromaDB client + collection helpers
217
+ ├── indexer/
218
+ │ ├── chunker.py — AST chunker (Python) + line-window fallback (all files)
219
+ │ ├── embedder.py — Ollama /api/embeddings wrapper
220
+ │ └── ingestion.py — Repo walker + indexing pipeline
221
+ ├── api/
222
+ │ └── retriever.py — ChromaDB cosine-similarity retrieval
223
+ ├── app/
224
+ │ ├── providers.py — Pluggable LLM backends (Ollama / OpenAI / Anthropic / Groq)
225
+ │ └── rag.py — RAG orchestration (retrieve → prompt → generate)
226
+ ├── cli/
227
+ │ └── main.py — Typer CLI (init, index, ask)
228
+ └── tests/
229
+ ├── test_chunker.py — Unit tests for chunking logic
230
+ └── test_retriever.py — Integration tests for retrieval
231
+ ```
232
+
233
+ ---
234
+
235
+ ## Running tests
236
+
237
+ ```bash
238
+ # Unit tests (no Ollama required)
239
+ pytest tests/test_chunker.py -v
240
+
241
+ # Integration tests (requires Ollama running)
242
+ pytest tests/ -v
243
+ ```
244
+
245
+ ---
246
+
247
+ ## Roadmap
248
+
249
+ - [ ] Tree-sitter chunking for JS / Go / Rust / Java
250
+ - [ ] `repoatlas search` — raw chunk retrieval without LLM
251
+ - [ ] `repoatlas watch` — incremental re-indexing on file change
252
+ - [ ] Web UI
253
+
254
+ ---
255
+
256
+ ## License
257
+
258
+ MIT — see [LICENSE](LICENSE)
File without changes
@@ -0,0 +1,80 @@
1
+ """
2
+ Vector retrieval — embeds a question and finds the most similar code chunks
3
+ using ChromaDB cosine similarity. No SQL, no server.
4
+ """
5
+ from typing import Optional
6
+
7
+ import chromadb
8
+
9
+ from indexer.embedder import get_embedding
10
+
11
+ # --------------------------------------------------------------------------- #
12
+ # Retrieval
13
+ # --------------------------------------------------------------------------- #
14
+
15
+
16
+ def retrieve(
17
+ question: str,
18
+ collection: chromadb.Collection,
19
+ repo_path: Optional[str] = None,
20
+ top_k: int = 5,
21
+ embed_model: Optional[str] = None,
22
+ ) -> list[dict]:
23
+ """
24
+ Embed *question* and return the *top_k* most similar chunks.
25
+
26
+ Parameters
27
+ ----------
28
+ question : str — natural-language question from the user
29
+ collection : chromadb.Collection — the RepoAtlas chunks collection
30
+ repo_path : str, optional — restrict results to a specific indexed repo
31
+ top_k : int — number of chunks to return (default 5)
32
+ embed_model: str, optional — override the Ollama embedding model
33
+
34
+ Returns
35
+ -------
36
+ list of dicts, each with keys:
37
+ repo_path, file_path, chunk_type, name,
38
+ start_line, end_line, code, similarity
39
+ """
40
+ kwargs = {"model": embed_model} if embed_model else {}
41
+ q_embedding = get_embedding(question, **kwargs)
42
+
43
+ query_kwargs: dict = {
44
+ "query_embeddings": [q_embedding],
45
+ "n_results": top_k,
46
+ "include": ["documents", "metadatas", "distances"],
47
+ }
48
+
49
+ if repo_path:
50
+ query_kwargs["where"] = {"repo_path": repo_path}
51
+
52
+ try:
53
+ results = collection.query(**query_kwargs)
54
+ except Exception as exc:
55
+ # ChromaDB raises if collection is empty or top_k > collection size
56
+ msg = str(exc).lower()
57
+ if any(k in msg for k in ("no elements", "cannot query", "index not found", "greater than")):
58
+ return []
59
+ raise
60
+
61
+ docs = results.get("documents", [[]])[0]
62
+ metas = results.get("metadatas", [[]])[0]
63
+ dists = results.get("distances", [[]])[0]
64
+
65
+ chunks = []
66
+ for doc, meta, dist in zip(docs, metas, dists):
67
+ # cosine space: distance ∈ [0, 2], but in practice [0, 1] for normalised
68
+ # vectors. similarity = 1 − distance gives a clean 0–1 score.
69
+ chunks.append({
70
+ "repo_path": meta.get("repo_path", ""),
71
+ "file_path": meta.get("file_path", ""),
72
+ "chunk_type": meta.get("chunk_type", ""),
73
+ "name": meta.get("name", ""),
74
+ "start_line": meta.get("start_line", 0),
75
+ "end_line": meta.get("end_line", 0),
76
+ "code": doc,
77
+ "similarity": round(1.0 - dist, 4),
78
+ })
79
+
80
+ return chunks
File without changes