feat(related): add semantic similarity discovery command

Implement `lore related` command for discovering semantically similar entities
using vector embeddings. Supports two modes:

Entity mode:
  lore related issues 42     # Find entities similar to issue #42
  lore related mrs 99        # Find entities similar to MR !99

Query mode:
  lore related "auth bug"    # Find entities matching free text query

Key features:
- Uses existing embedding infrastructure (nomic-embed-text via Ollama)
- Computes shared labels between source and results
- Shows similarity scores as percentage (0-100%)
- Warns when all results have low similarity (<30%)
- Warns for short queries (<=2 words) that may produce noisy results
- Filters out discussion/note documents, returning only issues and MRs
- Handles orphaned documents gracefully (skips if entity deleted)
- Robot mode JSON output with {ok, data, meta} envelope

Implementation details:
- distance_to_similarity() converts L2 distance to 0-1 score: 1/(1+distance)
- Uses saturating_add/saturating_mul for overflow safety on limit parameter
- Proper error handling for missing embeddings ("run lore embed first")
- Project scoping via -p flag with fuzzy matching

CLI integration:
- Added to autocorrect.rs command registry
- Added Related variant to Commands enum in cli/mod.rs
- Wired into main.rs with handle_related()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
teernisse
2026-02-26 11:06:01 -05:00
parent 7fdeafa330
commit 8657e10822
5 changed files with 711 additions and 10 deletions

View File

@@ -11,6 +11,7 @@ pub mod ingest;
pub mod init;
pub mod list;
pub mod me;
pub mod related;
pub mod search;
pub mod show;
pub mod stats;
@@ -48,6 +49,7 @@ pub use list::{
print_list_notes, print_list_notes_json, query_notes, run_list_issues, run_list_mrs,
};
pub use me::run_me;
pub use related::{RelatedResponse, print_related_human, print_related_json, run_related};
pub use search::{
SearchCliFilters, SearchResponse, print_search_results, print_search_results_json, run_search,
};