odino 0.1.1__tar.gz → 0.1.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: odino
3
- Version: 0.1.1
3
+ Version: 0.1.4
4
4
  Summary: Local semantic search CLI tool for codebases using embeddings
5
5
  Home-page: https://github.com/cesp99/odino
6
6
  Author: Carlo Esposito
@@ -36,6 +36,13 @@ Dynamic: requires-python
36
36
 
37
37
  A fast local semantic search tool that helps you find code using natural language queries. No internet required, everything runs locally using the embeddinggemma-300m model.
38
38
 
39
+ <p align="center">
40
+ <a href="https://pypi.org/project/odino/"><img alt="PyPI" src="https://badge.fury.io/py/odino.svg"></a>
41
+ <a href="https://www.gnu.org/licenses/gpl-3.0"><img alt="License: GPL v3" src="https://img.shields.io/badge/License-GPLv3-blue.svg"></a>
42
+ <a href="https://pypi.org/project/odino"><img alt="Supported Python Versions" src="https://img.shields.io/pypi/pyversions/odino?color=brightgreen"></a>
43
+ <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
44
+ </p>
45
+
39
46
  ## Quick Start
40
47
 
41
48
  Install Odino directly from PyPI:
@@ -235,6 +242,18 @@ For advanced memory management configuration and more detailed troubleshooting,
235
242
  4. Add tests if applicable
236
243
  5. Submit a pull request
237
244
 
245
+ ## For AI Agents
246
+
247
+ AI agents working with this codebase should refer to the [ODINO.md](ODINO.md) file for detailed usage instructions and best practices. This file contains comprehensive documentation on:
248
+
249
+ - **Basic Commands**: Indexing and searching operations
250
+ - **Advanced Search Options**: Filtering, path targeting, and result limiting
251
+ - **Semantic Search Capabilities**: How to find files by meaning rather than exact keywords
252
+ - **Best Practices**: When to use Odino vs traditional grep, filtering strategies, and query optimization
253
+ - **Workflow Examples**: Real-world usage patterns for code discovery
254
+
255
+ The ODINO.md file is specifically designed to help AI agents understand how to effectively use Odino's semantic search capabilities to navigate and understand codebases during development tasks.
256
+
238
257
  ## License
239
258
 
240
259
  This project is licensed under the GNU General Public License v3.0 - see [LICENSE](LICENSE) file for details.
@@ -2,6 +2,13 @@
2
2
 
3
3
  A fast local semantic search tool that helps you find code using natural language queries. No internet required, everything runs locally using the embeddinggemma-300m model.
4
4
 
5
+ <p align="center">
6
+ <a href="https://pypi.org/project/odino/"><img alt="PyPI" src="https://badge.fury.io/py/odino.svg"></a>
7
+ <a href="https://www.gnu.org/licenses/gpl-3.0"><img alt="License: GPL v3" src="https://img.shields.io/badge/License-GPLv3-blue.svg"></a>
8
+ <a href="https://pypi.org/project/odino"><img alt="Supported Python Versions" src="https://img.shields.io/pypi/pyversions/odino?color=brightgreen"></a>
9
+ <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
10
+ </p>
11
+
5
12
  ## Quick Start
6
13
 
7
14
  Install Odino directly from PyPI:
@@ -201,6 +208,18 @@ For advanced memory management configuration and more detailed troubleshooting,
201
208
  4. Add tests if applicable
202
209
  5. Submit a pull request
203
210
 
211
+ ## For AI Agents
212
+
213
+ AI agents working with this codebase should refer to the [ODINO.md](ODINO.md) file for detailed usage instructions and best practices. This file contains comprehensive documentation on:
214
+
215
+ - **Basic Commands**: Indexing and searching operations
216
+ - **Advanced Search Options**: Filtering, path targeting, and result limiting
217
+ - **Semantic Search Capabilities**: How to find files by meaning rather than exact keywords
218
+ - **Best Practices**: When to use Odino vs traditional grep, filtering strategies, and query optimization
219
+ - **Workflow Examples**: Real-world usage patterns for code discovery
220
+
221
+ The ODINO.md file is specifically designed to help AI agents understand how to effectively use Odino's semantic search capabilities to navigate and understand codebases during development tasks.
222
+
204
223
  ## License
205
224
 
206
225
  This project is licensed under the GNU General Public License v3.0 - see [LICENSE](LICENSE) file for details.
@@ -4,6 +4,6 @@ Odino - Local Semantic Search CLI
4
4
  A local-only command-line tool for semantic search in code and text files.
5
5
  """
6
6
 
7
- __version__ = "0.1.0"
7
+ __version__ = "0.1.4"
8
8
  __author__ = "Carlo Esposito"
9
- __email__ = "carlo@aploi.de"
9
+ __email__ = "carlo@aploi.de"
@@ -23,23 +23,58 @@ app = typer.Typer(
23
23
  )
24
24
  console = Console()
25
25
 
26
+
26
27
  def version_callback(value: bool) -> None:
27
28
  """Show version information."""
28
29
  if value:
29
- console.print("Odino v1.0.0 - Local Semantic Search CLI")
30
- console.print("Using embeddinggemma-300m model for fast indexing")
30
+ console.print("Odino v0.1.4 - Local Semantic Search CLI")
31
31
  raise typer.Exit()
32
32
 
33
33
 
34
34
  @app.callback(invoke_without_command=True)
35
35
  def main(
36
36
  ctx: typer.Context,
37
- version: Annotated[bool, typer.Option("--version", "-v", help="Show version and exit", callback=version_callback, is_eager=True)] = None,
38
- query_text: Annotated[Optional[str], typer.Option("--query", "-q", help="Search query in natural language")] = None,
39
- results: Annotated[Optional[int], typer.Option("--results", "-r", help="Number of results to return", min=1, max=100)] = None,
40
- include: Annotated[Optional[str], typer.Option("--include", help="Include only files matching this pattern (glob)")] = None,
41
- exclude: Annotated[Optional[str], typer.Option("--exclude", help="Exclude files matching this pattern (glob)")] = None,
42
- path: Annotated[Optional[Path], typer.Option("--path", "-p", help="Directory to search in", exists=True, file_okay=False, dir_okay=True)] = None,
37
+ version: Annotated[
38
+ bool,
39
+ typer.Option(
40
+ "--version",
41
+ "-v",
42
+ help="Show version and exit",
43
+ callback=version_callback,
44
+ is_eager=True,
45
+ ),
46
+ ] = None,
47
+ query_text: Annotated[
48
+ Optional[str],
49
+ typer.Option("--query", "-q", help="Search query in natural language"),
50
+ ] = None,
51
+ results: Annotated[
52
+ Optional[int],
53
+ typer.Option(
54
+ "--results", "-r", help="Number of results to return", min=1, max=100
55
+ ),
56
+ ] = None,
57
+ include: Annotated[
58
+ Optional[str],
59
+ typer.Option(
60
+ "--include", help="Include only files matching this pattern (glob)"
61
+ ),
62
+ ] = None,
63
+ exclude: Annotated[
64
+ Optional[str],
65
+ typer.Option("--exclude", help="Exclude files matching this pattern (glob)"),
66
+ ] = None,
67
+ path: Annotated[
68
+ Optional[Path],
69
+ typer.Option(
70
+ "--path",
71
+ "-p",
72
+ help="Directory to search in",
73
+ exists=True,
74
+ file_okay=False,
75
+ dir_okay=True,
76
+ ),
77
+ ] = None,
43
78
  ) -> None:
44
79
  """Odino - Local semantic search CLI for codebases."""
45
80
  if ctx.invoked_subcommand is None:
@@ -96,43 +131,50 @@ def index(
96
131
  """Index files in a directory for semantic search."""
97
132
  try:
98
133
  config = load_config(path)
99
-
134
+
100
135
  # Update config with command line options
101
136
  config["model_name"] = model
102
137
  config["chunk_size"] = chunk_size
103
138
  config["chunk_overlap"] = chunk_overlap
104
-
139
+
105
140
  save_config(path, config)
106
-
107
- console.print(Panel.fit(
108
- f"[bold blue]Indexing directory:[/bold blue] {path.absolute()}\n"
109
- f"[bold blue]Model:[/bold blue] {model}\n"
110
- f"[bold blue]Chunk size:[/bold blue] {chunk_size}\n"
111
- f"[bold blue]Chunk overlap:[/bold blue] {chunk_overlap}",
112
- title="Odino Indexer",
113
- border_style="blue"
114
- ))
115
-
141
+
142
+ console.print(
143
+ Panel.fit(
144
+ f"[bold blue]Indexing directory:[/bold blue] {path.absolute()}\n"
145
+ f"[bold blue]Model:[/bold blue] {model}\n"
146
+ f"[bold blue]Chunk size:[/bold blue] {chunk_size}\n"
147
+ f"[bold blue]Chunk overlap:[/bold blue] {chunk_overlap}",
148
+ title="Odino Indexer",
149
+ border_style="blue",
150
+ )
151
+ )
152
+
116
153
  indexer = Indexer(path, console)
117
-
154
+
118
155
  with Progress(
119
156
  SpinnerColumn(),
120
157
  TextColumn("[progress.description]{task.description}"),
121
158
  console=console,
122
159
  ) as progress:
123
160
  task = progress.add_task("Initializing...", total=None)
124
-
125
- stats = indexer.index(force=force, progress_callback=lambda msg: progress.update(task, description=msg))
126
-
127
- console.print(Panel.fit(
128
- f"[bold green]Indexing complete![/bold green]\n"
129
- f"Files indexed: {stats['files_indexed']}\n"
130
- f"Chunks created: {stats['chunks_created']}\n"
131
- f"Total size: {stats['total_size_mb']:.1f} MB",
132
- title="Success",
133
- border_style="green"
134
- ))
135
-
161
+
162
+ stats = indexer.index(
163
+ force=force,
164
+ progress_callback=lambda msg: progress.update(task, description=msg),
165
+ )
166
+
167
+ console.print(
168
+ Panel.fit(
169
+ f"[bold green]Indexing complete![/bold green]\n"
170
+ f"Files indexed: {stats['files_indexed']}\n"
171
+ f"Chunks created: {stats['chunks_created']}\n"
172
+ f"Total size: {stats['total_size_mb']:.1f} MB",
173
+ title="Success",
174
+ border_style="green",
175
+ )
176
+ )
177
+
136
178
  except Exception as e:
137
179
  console.print(f"[bold red]Error during indexing:[/bold red] {e}")
138
180
  raise typer.Exit(1)
@@ -175,19 +217,23 @@ def query(
175
217
  """Search indexed files using natural language queries."""
176
218
  try:
177
219
  config = load_config(path)
178
-
179
- effective_results = results if results is not None else config.get("max_results", 2)
180
-
181
- console.print(Panel.fit(
182
- f"[bold blue]Searching:[/bold blue] {query_text}\n"
183
- f"[bold blue]Directory:[/bold blue] {path.absolute()}\n"
184
- f"[bold blue]Max results:[/bold blue] {effective_results}",
185
- title="Odino Search",
186
- border_style="blue"
187
- ))
188
-
220
+
221
+ effective_results = (
222
+ results if results is not None else config.get("max_results", 2)
223
+ )
224
+
225
+ console.print(
226
+ Panel.fit(
227
+ f"[bold blue]Searching:[/bold blue] {query_text}\n"
228
+ f"[bold blue]Directory:[/bold blue] {path.absolute()}\n"
229
+ f"[bold blue]Max results:[/bold blue] {effective_results}",
230
+ title="Odino Search",
231
+ border_style="blue",
232
+ )
233
+ )
234
+
189
235
  searcher = Searcher(path, console)
190
-
236
+
191
237
  with console.status("[bold blue]Searching..."):
192
238
  search_results = searcher.search(
193
239
  query_text,
@@ -195,23 +241,23 @@ def query(
195
241
  include_pattern=include,
196
242
  exclude_pattern=exclude,
197
243
  )
198
-
244
+
199
245
  if not search_results:
200
246
  console.print("[yellow]No results found. Try a different query.[/yellow]")
201
247
  return
202
-
248
+
203
249
  # Display results in a table
204
250
  table = Table(show_header=True, header_style="bold magenta")
205
251
  table.add_column("File", style="cyan", no_wrap=False)
206
252
  table.add_column("Score", style="green", width=8)
207
253
  table.add_column("Content", style="white")
208
-
254
+
209
255
  for result in search_results:
210
256
  file_path = result.file_path
211
257
  score = f"{result.score:.3f}"
212
258
  content = result.content
213
259
  start_line = result.start_line
214
-
260
+
215
261
  # Create syntax highlighted content
216
262
  try:
217
263
  syntax = Syntax(
@@ -226,10 +272,10 @@ def query(
226
272
  except Exception:
227
273
  # Fallback to plain text
228
274
  table.add_row(file_path, score, content)
229
-
275
+
230
276
  console.print(table)
231
277
  console.print(f"\n[bold green]Found {len(search_results)} results[/bold green]")
232
-
278
+
233
279
  except Exception as e:
234
280
  console.print(f"[bold red]Error during search:[/bold red] {e}")
235
281
  raise typer.Exit(1)
@@ -249,37 +295,37 @@ def status(
249
295
  try:
250
296
  config = load_config(path)
251
297
  odino_dir = path / ".odino"
252
-
298
+
253
299
  if not odino_dir.exists():
254
300
  console.print("[yellow]No index found. Run 'odino index' first.[/yellow]")
255
301
  return
256
-
302
+
257
303
  # Get index info
258
304
  from .searcher import Searcher
305
+
259
306
  searcher = Searcher(path, config)
260
307
  index_info = searcher.get_index_info()
261
-
262
- console.print(Panel.fit(
263
- f"[bold blue]Configuration:[/bold blue]\n"
264
- f" Model: {config['model_name']}\n"
265
- f" Chunk size: {config['chunk_size']}\n"
266
- f" Chunk overlap: {config['chunk_overlap']}\n"
267
- f" Max results: {config['max_results']}\n\n"
268
- f"[bold blue]Index Status:[/bold blue]\n"
269
- f" Total chunks: {index_info['total_chunks']}\n"
270
- f" Indexed files: {index_info['indexed_files']}\n"
271
- f" Last updated: {index_info['last_updated']}",
272
- title="Odino Status",
273
- border_style="blue"
274
- ))
275
-
308
+
309
+ console.print(
310
+ Panel.fit(
311
+ f"[bold blue]Configuration:[/bold blue]\n"
312
+ f" Model: {config['model_name']}\n"
313
+ f" Chunk size: {config['chunk_size']}\n"
314
+ f" Chunk overlap: {config['chunk_overlap']}\n"
315
+ f" Max results: {config['max_results']}\n\n"
316
+ f"[bold blue]Index Status:[/bold blue]\n"
317
+ f" Total chunks: {index_info['total_chunks']}\n"
318
+ f" Indexed files: {index_info['indexed_files']}\n"
319
+ f" Last updated: {index_info['last_updated']}",
320
+ title="Odino Status",
321
+ border_style="blue",
322
+ )
323
+ )
324
+
276
325
  except Exception as e:
277
326
  console.print(f"[bold red]Error getting status:[/bold red] {e}")
278
327
  raise typer.Exit(1)
279
328
 
280
329
 
281
-
282
-
283
-
284
330
  if __name__ == "__main__":
285
- app()
331
+ app()