Initial upload: shell-history-semantic-search v0.1.0
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-03-22 18:15:27 +00:00
parent c9976b6f04
commit c49a5d3901

View File

@@ -0,0 +1,109 @@
import click
import json
import logging
from datetime import datetime
from ..core import SearchEngine, IndexingService
logger = logging.getLogger(__name__)
@click.group()
@click.option("-v", "--verbose", count=True, help="Increase verbosity")
def cli(verbose: int) -> None:
log_level = logging.WARNING
if verbose == 1:
log_level = logging.INFO
elif verbose >= 2:
log_level = logging.DEBUG
logging.basicConfig(level=log_level, format="%(levelname)s: %(message)s")
@cli.command()
@click.option("--shell", type=str, help="Index only specific shell (bash, zsh, fish)")
def index(shell: str | None) -> None:
click.echo("Indexing shell history...")
indexing_service = IndexingService()
shell_type = shell.lower() if shell else None
result = indexing_service.index_shell_history(shell_type)
click.echo(
f"Indexed {result['total_indexed']} commands "
f"(skipped {result['total_skipped']} duplicates)"
)
@cli.command()
@click.argument("query")
@click.option("--limit", "-n", type=int, default=10, help="Number of results to return")
@click.option("--shell", type=str, help="Filter by shell type (bash, zsh, fish)")
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
def search(query: str, limit: int, shell: str | None, json_output: bool) -> None:
search_engine = SearchEngine()
shell_type = shell.lower() if shell else None
results = search_engine.search(query, limit=limit, shell_type=shell_type)
if not results:
click.echo("No results found.")
return
if json_output:
output = [
{
"command": r.command,
"shell": r.shell_type,
"timestamp": r.timestamp,
"similarity": round(r.similarity, 4),
}
for r in results
]
click.echo(json.dumps(output, indent=2))
else:
for i, result in enumerate(results, 1):
timestamp_str = ""
if result.timestamp:
dt = datetime.fromtimestamp(result.timestamp)
timestamp_str = dt.strftime("%Y-%m-%d %H:%M")
similarity_pct = result.similarity * 100
click.echo(f"{i}. [{result.shell_type}] {timestamp_str}")
click.echo(f" {result.command}")
click.echo(f" Similarity: {similarity_pct:.1f}%")
click.echo()
@cli.command()
@click.option("--json", "json_output", is_flag=True, help="Output as JSON")
def stats(json_output: bool) -> None:
search_engine = SearchEngine()
stats_data = search_engine.get_stats()
if json_output:
click.echo(json.dumps(stats_data, indent=2))
else:
click.echo("Shell History Search Statistics")
click.echo("=" * 40)
click.echo(f"Total commands: {stats_data['total_commands']}")
click.echo(f"Total embeddings: {stats_data['total_embeddings']}")
click.echo(f"Embedding model: {stats_data['embedding_model']}")
click.echo(f"Embedding dimension: {stats_data['embedding_dim']}")
click.echo()
click.echo("Commands by shell:")
for shell_type, count in stats_data["shell_counts"].items():
click.echo(f" {shell_type}: {count}")
@cli.command()
@click.confirmation_option(prompt="Are you sure you want to clear all indexed data?")
def clear() -> None:
search_engine = SearchEngine()
search_engine.clear_all()
click.echo("All indexed data has been cleared.")
if __name__ == "__main__":
cli()