java-codebase-rag 0.6.7__py3-none-any.whl → 0.9.0__py3-none-any.whl
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.
- ast_java.py +8 -3
- build_ast_graph.py +72 -16
- graph_enrich.py +2 -1
- graph_types.py +133 -0
- java_codebase_rag/_fdlimit.py +10 -2
- java_codebase_rag/_stdio.py +32 -0
- java_codebase_rag/cli.py +149 -25
- java_codebase_rag/config.py +128 -9
- java_codebase_rag/install_data/agents/explorer-rag-cli.md +148 -0
- java_codebase_rag/install_data/agents/explorer-rag-enhanced.md +78 -232
- java_codebase_rag/install_data/skills/explore-codebase/SKILL.md +49 -88
- java_codebase_rag/install_data/skills/explore-codebase-cli/SKILL.md +183 -0
- java_codebase_rag/installer.py +720 -107
- java_codebase_rag/jrag.py +4405 -0
- java_codebase_rag/jrag_envelope.py +1085 -0
- java_codebase_rag/jrag_hints.py +204 -0
- java_codebase_rag/jrag_render.py +697 -0
- java_codebase_rag/lance_optimize.py +18 -0
- java_codebase_rag/pipeline.py +34 -0
- {java_codebase_rag-0.6.7.dist-info → java_codebase_rag-0.9.0.dist-info}/METADATA +137 -94
- java_codebase_rag-0.9.0.dist-info/RECORD +43 -0
- {java_codebase_rag-0.6.7.dist-info → java_codebase_rag-0.9.0.dist-info}/WHEEL +1 -1
- {java_codebase_rag-0.6.7.dist-info → java_codebase_rag-0.9.0.dist-info}/entry_points.txt +1 -0
- {java_codebase_rag-0.6.7.dist-info → java_codebase_rag-0.9.0.dist-info}/top_level.txt +2 -0
- java_index_flow_lancedb.py +34 -19
- java_ontology.py +12 -0
- ladybug_queries.py +233 -52
- mcp_hints.py +6 -6
- mcp_v2.py +276 -632
- resolve_service.py +649 -0
- search_lancedb.py +159 -4
- server.py +31 -12
- java_codebase_rag-0.6.7.dist-info/RECORD +0 -34
- {java_codebase_rag-0.6.7.dist-info → java_codebase_rag-0.9.0.dist-info}/licenses/LICENSE +0 -0
search_lancedb.py
CHANGED
|
@@ -41,6 +41,11 @@ JAVA_ENRICHED_COLUMNS: tuple[str, ...] = (
|
|
|
41
41
|
"capabilities",
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
+
# Over-fetch multiplier for dedup: fetch 4x to absorb per-FQN chunk multiplicity
|
|
45
|
+
# so that after collapsing by primary_type_fqn, a page stays full and the +1
|
|
46
|
+
# truncation sentinel survives. The formula: need = max((limit + offset) * 4, limit + offset + 1)
|
|
47
|
+
DEDUP_OVERFETCH = 4
|
|
48
|
+
|
|
44
49
|
VECTOR_COLUMN = "embedding"
|
|
45
50
|
_FTS_READY: set[tuple[str, str]] = set()
|
|
46
51
|
_FTS_LOCK = threading.Lock()
|
|
@@ -201,6 +206,14 @@ _ROLE_SCORE_WEIGHTS: dict[str, float] = {
|
|
|
201
206
|
"DTO": -0.08,
|
|
202
207
|
}
|
|
203
208
|
|
|
209
|
+
# Theoretical maximum for hybrid composite score (used for display normalization).
|
|
210
|
+
# Hybrid sort metric: raw_rrf * (import_factor if import_heavy else 1)
|
|
211
|
+
# + role_weight + symbol_bonus
|
|
212
|
+
# where raw_rrf ≤ 2/(k+1) for 2-list RRF, role_weight ≤ max(_ROLE_SCORE_WEIGHTS),
|
|
213
|
+
# and symbol_bonus ≤ _SYMBOL_MATCH_BONUS_CAP + _TYPE_MATCH_BONUS_CAP + _ACTION_VERB_BONUS.
|
|
214
|
+
# The import factor is ≤ 1, so we use the raw max (2/61).
|
|
215
|
+
_HYBRID_SCORE_MAX = (2.0 / 61.0) + max(_ROLE_SCORE_WEIGHTS.values()) + _SYMBOL_MATCH_BONUS_CAP + _TYPE_MATCH_BONUS_CAP + _ACTION_VERB_BONUS
|
|
216
|
+
|
|
204
217
|
|
|
205
218
|
def _query_tokens(query: str) -> set[str]:
|
|
206
219
|
"""Lowercased alpha-only tokens from the query, minus stopwords, len >= 3.
|
|
@@ -353,7 +366,7 @@ def _hybrid_sort_key(r: dict) -> float:
|
|
|
353
366
|
comps["hybrid_rrf"] = s
|
|
354
367
|
if r.get("_hints", {}).get("import_heavy"):
|
|
355
368
|
s *= _IMPORT_HYBRID_SCORE_FACTOR
|
|
356
|
-
comps["import_penalty"] = _IMPORT_HYBRID_SCORE_FACTOR
|
|
369
|
+
comps["import_penalty"] = 1.0 - _IMPORT_HYBRID_SCORE_FACTOR
|
|
357
370
|
s += _role_weight(r)
|
|
358
371
|
s += float(comps.get("symbol_bonus", 0.0))
|
|
359
372
|
return -s
|
|
@@ -376,7 +389,8 @@ def explain_score_components(
|
|
|
376
389
|
comps = {}
|
|
377
390
|
parts: list[str] = []
|
|
378
391
|
if hybrid:
|
|
379
|
-
|
|
392
|
+
# Prefer rrf_raw (added by PR-SEARCH-1a) for explanation
|
|
393
|
+
rrf = comps.get("rrf_raw") or comps.get("hybrid_rrf")
|
|
380
394
|
if rrf is not None:
|
|
381
395
|
parts.append(f"rrf={float(rrf):.3f}")
|
|
382
396
|
else:
|
|
@@ -403,6 +417,46 @@ def l2_distance_to_score(distance: float) -> float:
|
|
|
403
417
|
return 1.0 - distance * distance / 2.0
|
|
404
418
|
|
|
405
419
|
|
|
420
|
+
def _effective_distance(comps: dict[str, float]) -> float:
|
|
421
|
+
"""Compute the adjusted distance used for sorting.
|
|
422
|
+
|
|
423
|
+
Matches _vector_sort_key logic: distance + import_penalty - role_weight - symbol_bonus.
|
|
424
|
+
"""
|
|
425
|
+
d = comps.get("distance", 0.0)
|
|
426
|
+
d += comps.get("import_penalty", 0.0)
|
|
427
|
+
d -= comps.get("role_weight", 0.0)
|
|
428
|
+
d -= comps.get("symbol_bonus", 0.0)
|
|
429
|
+
return d
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _clamp01(x: float) -> float:
|
|
433
|
+
"""Clamp a value to the [0.0, 1.0] range."""
|
|
434
|
+
if x < 0.0:
|
|
435
|
+
return 0.0
|
|
436
|
+
if x > 1.0:
|
|
437
|
+
return 1.0
|
|
438
|
+
return x
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
def _hybrid_post_sort_normalization(rows: list[dict]) -> None:
|
|
442
|
+
"""Set honest displayed scores for hybrid search after sorting.
|
|
443
|
+
|
|
444
|
+
Reconstructs the composite score (raw_rrf * import_factor + role_weight + symbol_bonus)
|
|
445
|
+
and normalizes by _HYBRID_SCORE_MAX to ensure rank-monotonicity.
|
|
446
|
+
|
|
447
|
+
Mutates rows in-place, replacing _score with the normalized value.
|
|
448
|
+
"""
|
|
449
|
+
for r in rows:
|
|
450
|
+
comps = r.setdefault("_score_components", {})
|
|
451
|
+
raw = comps.get("hybrid_rrf", 0.0)
|
|
452
|
+
comps["rrf_raw"] = raw # preserve raw RRF for --explain. NOTE: when graph_expand + hybrid combine (Phase 2), _rrf_merge below overwrites this with graph-RRF, so --explain would show graph-RRF not hybrid-RRF.
|
|
453
|
+
s = raw
|
|
454
|
+
if r.get("_hints", {}).get("import_heavy"):
|
|
455
|
+
s *= _IMPORT_HYBRID_SCORE_FACTOR
|
|
456
|
+
s += comps.get("role_weight", 0.0) + comps.get("symbol_bonus", 0.0)
|
|
457
|
+
r["_score"] = _clamp01(s / _HYBRID_SCORE_MAX)
|
|
458
|
+
|
|
459
|
+
|
|
406
460
|
def _escape_like_fragment(s: str) -> str:
|
|
407
461
|
return s.replace("'", "''")
|
|
408
462
|
|
|
@@ -534,6 +588,15 @@ def _search_one_table(
|
|
|
534
588
|
for r in rows:
|
|
535
589
|
r["_kind"] = kind
|
|
536
590
|
r["_hybrid"] = False
|
|
591
|
+
# Populate `_score` from `_distance` so the SearchHit.score reflects
|
|
592
|
+
# relevance. The hybrid branch sets `_score` from `_relevance_score`
|
|
593
|
+
# above; without this, non-hybrid (default) search left `_score` unset
|
|
594
|
+
# and mcp_v2._row_to_search_hit fell back to 0.0 for EVERY hit —
|
|
595
|
+
# ranking still worked (the sort key uses `_distance` directly) but the
|
|
596
|
+
# exposed score was always 0.0, making results look unranked.
|
|
597
|
+
d = r.get("_distance")
|
|
598
|
+
if d is not None:
|
|
599
|
+
r["_score"] = l2_distance_to_score(float(d))
|
|
537
600
|
r["start"] = coerce_position_field(r.get("start"))
|
|
538
601
|
r["end"] = coerce_position_field(r.get("end"))
|
|
539
602
|
return rows
|
|
@@ -781,9 +844,72 @@ def _rrf_merge(
|
|
|
781
844
|
existing["_rrf_score"] = float(existing.get("_rrf_score", 0.0)) + contribution
|
|
782
845
|
merged = list(pool.values())
|
|
783
846
|
merged.sort(key=lambda r: -float(r.get("_rrf_score", 0.0)))
|
|
847
|
+
# Normalize displayed _rrf_score to [0,1] by theoretical max
|
|
848
|
+
# RRF max = Σ weight·1/(k+rank+1); theoretical max when all rows are rank 0
|
|
849
|
+
# with weight 1.0 = num_lists / (k + 1)
|
|
850
|
+
num_lists = len(lists)
|
|
851
|
+
max_rrf = num_lists / (k + 1)
|
|
852
|
+
for r in merged:
|
|
853
|
+
raw_score = float(r.get("_rrf_score", 0.0))
|
|
854
|
+
comps = r.setdefault("_score_components", {})
|
|
855
|
+
comps["rrf_raw"] = raw_score
|
|
856
|
+
r["_rrf_score"] = _clamp01(raw_score / max_rrf)
|
|
784
857
|
return merged
|
|
785
858
|
|
|
786
859
|
|
|
860
|
+
def _dedup_by_fqn(rows: list[dict], dedup_by_fqn: bool = True) -> list[dict]:
|
|
861
|
+
"""Deduplicate rows by primary_type_fqn (java table only).
|
|
862
|
+
|
|
863
|
+
When dedup_by_fqn is True, collapses multiple chunks of the same
|
|
864
|
+
primary_type_fqn into one row (first-seen-wins, since rows are pre-sorted
|
|
865
|
+
so the first is the best chunk). Each survivor gets a _chunks_collapsed
|
|
866
|
+
field (>=1) counting how many rows were collapsed into it.
|
|
867
|
+
|
|
868
|
+
Rows without primary_type_fqn (sql/yaml tables) get a unique __id:<id>
|
|
869
|
+
key so they pass through unchanged (each row is unique).
|
|
870
|
+
|
|
871
|
+
When dedup_by_fqn is False, returns rows unchanged (regression guard).
|
|
872
|
+
"""
|
|
873
|
+
if not dedup_by_fqn:
|
|
874
|
+
# Non-dedup path: return unchanged, byte-identical to prior behavior
|
|
875
|
+
return rows
|
|
876
|
+
|
|
877
|
+
deduped: list[dict] = []
|
|
878
|
+
seen_keys: dict[str, dict] = {}
|
|
879
|
+
collapsed_counts: dict[str, int] = {}
|
|
880
|
+
|
|
881
|
+
for row in rows:
|
|
882
|
+
# Build dedup key: primary_type_fqn for java rows, unique __id:<id> for sql/yaml
|
|
883
|
+
fqn = row.get("primary_type_fqn")
|
|
884
|
+
if fqn:
|
|
885
|
+
key = str(fqn)
|
|
886
|
+
else:
|
|
887
|
+
# sql/yaml rows have no primary_type_fqn → unique key per row
|
|
888
|
+
row_id = row.get("id") or id(row)
|
|
889
|
+
key = f"__id:{row_id}"
|
|
890
|
+
|
|
891
|
+
if key not in seen_keys:
|
|
892
|
+
# First occurrence: keep it
|
|
893
|
+
seen_keys[key] = row
|
|
894
|
+
collapsed_counts[key] = 1
|
|
895
|
+
deduped.append(row)
|
|
896
|
+
else:
|
|
897
|
+
# Duplicate: increment collapse count, discard this row
|
|
898
|
+
collapsed_counts[key] += 1
|
|
899
|
+
|
|
900
|
+
# Annotate each survivor with _chunks_collapsed
|
|
901
|
+
for row in deduped:
|
|
902
|
+
fqn = row.get("primary_type_fqn")
|
|
903
|
+
if fqn:
|
|
904
|
+
key = str(fqn)
|
|
905
|
+
else:
|
|
906
|
+
row_id = row.get("id") or id(row)
|
|
907
|
+
key = f"__id:{row_id}"
|
|
908
|
+
row["_chunks_collapsed"] = collapsed_counts[key]
|
|
909
|
+
|
|
910
|
+
return deduped
|
|
911
|
+
|
|
912
|
+
|
|
787
913
|
def run_search(
|
|
788
914
|
query: str,
|
|
789
915
|
*,
|
|
@@ -810,6 +936,7 @@ def run_search(
|
|
|
810
936
|
exclude_roles: list[str] | None = None,
|
|
811
937
|
capability: str | None = None,
|
|
812
938
|
capability_in: list[str] | None = None,
|
|
939
|
+
dedup_by_fqn: bool = False,
|
|
813
940
|
) -> list[dict]:
|
|
814
941
|
effective_hybrid = hybrid
|
|
815
942
|
effective_fts = fts_text
|
|
@@ -843,7 +970,16 @@ def run_search(
|
|
|
843
970
|
fts_for_hybrid = effective_fts if effective_fts is not None else query
|
|
844
971
|
|
|
845
972
|
db = lancedb.connect(uri)
|
|
846
|
-
|
|
973
|
+
if dedup_by_fqn:
|
|
974
|
+
# Over-fetch to absorb per-FQN chunk multiplicity: fetch 4x so that
|
|
975
|
+
# after collapsing, the page stays full and the +1 truncation sentinel survives.
|
|
976
|
+
# The 4× factor assumes typical per-FQN chunk multiplicity; a single type with
|
|
977
|
+
# many high-ranking chunks (e.g. generated/God classes) could starve the page or
|
|
978
|
+
# make the +1 truncation sentinel unreliable; Phase 1 may revisit adaptive over-fetch (plan risk #1).
|
|
979
|
+
need = max((limit + offset) * DEDUP_OVERFETCH, limit + offset + 1)
|
|
980
|
+
else:
|
|
981
|
+
# Non-dedup path: exact fetch as before
|
|
982
|
+
need = max(limit + offset, 1)
|
|
847
983
|
|
|
848
984
|
extra_java = _build_extra_predicates(
|
|
849
985
|
columns=_table_columns(uri, TABLES["java"], db),
|
|
@@ -853,7 +989,7 @@ def run_search(
|
|
|
853
989
|
capability=capability, capability_in=capability_in,
|
|
854
990
|
) if "java" in table_keys else []
|
|
855
991
|
|
|
856
|
-
skip_role_weight = bool(role or role_in)
|
|
992
|
+
skip_role_weight = bool(role or role_in or exclude_roles)
|
|
857
993
|
query_toks = _query_tokens(query)
|
|
858
994
|
|
|
859
995
|
if len(table_keys) == 1:
|
|
@@ -878,8 +1014,15 @@ def run_search(
|
|
|
878
1014
|
_apply_symbol_bonus(rows, query_toks)
|
|
879
1015
|
if effective_hybrid:
|
|
880
1016
|
rows.sort(key=_hybrid_sort_key)
|
|
1017
|
+
# Hybrid: set honest displayed score from composite sort metric, clamped to [0,1]
|
|
1018
|
+
_hybrid_post_sort_normalization(rows)
|
|
881
1019
|
else:
|
|
882
1020
|
rows.sort(key=_vector_sort_key)
|
|
1021
|
+
# Vector: set honest displayed score from adjusted distance, clamped to [0,1]
|
|
1022
|
+
for r in rows:
|
|
1023
|
+
comps = r.setdefault("_score_components", {})
|
|
1024
|
+
effective_dist = _effective_distance(comps)
|
|
1025
|
+
r["_score"] = _clamp01(l2_distance_to_score(effective_dist))
|
|
883
1026
|
|
|
884
1027
|
if graph_expand and key == "java" and expand_depth > 0:
|
|
885
1028
|
rows = _graph_expand_merge(
|
|
@@ -893,6 +1036,9 @@ def run_search(
|
|
|
893
1036
|
ladybug_path=ladybug_path,
|
|
894
1037
|
)
|
|
895
1038
|
|
|
1039
|
+
# Dedup by primary_type_fqn after all sorting/merging, before windowing
|
|
1040
|
+
rows = _dedup_by_fqn(rows, dedup_by_fqn=dedup_by_fqn)
|
|
1041
|
+
|
|
896
1042
|
window = rows[offset : offset + limit]
|
|
897
1043
|
if context_neighbors > 0 and key == "java":
|
|
898
1044
|
_attach_neighbor_context(window, db=db, neighbors=context_neighbors, uri=uri)
|
|
@@ -922,6 +1068,15 @@ def run_search(
|
|
|
922
1068
|
r["_skip_role_weight"] = True
|
|
923
1069
|
_apply_symbol_bonus(merged, query_toks)
|
|
924
1070
|
merged.sort(key=_vector_sort_key)
|
|
1071
|
+
# Vector: set honest displayed score from adjusted distance, clamped to [0,1]
|
|
1072
|
+
for r in merged:
|
|
1073
|
+
comps = r.setdefault("_score_components", {})
|
|
1074
|
+
effective_dist = _effective_distance(comps)
|
|
1075
|
+
r["_score"] = _clamp01(l2_distance_to_score(effective_dist))
|
|
1076
|
+
|
|
1077
|
+
# Dedup by primary_type_fqn after all sorting/merging, before windowing
|
|
1078
|
+
merged = _dedup_by_fqn(merged, dedup_by_fqn=dedup_by_fqn)
|
|
1079
|
+
|
|
925
1080
|
window = merged[offset : offset + limit]
|
|
926
1081
|
if context_neighbors > 0:
|
|
927
1082
|
_attach_neighbor_context(window, db=db, neighbors=context_neighbors, uri=uri)
|
server.py
CHANGED
|
@@ -26,7 +26,8 @@ from java_codebase_rag.config import (
|
|
|
26
26
|
from ladybug_queries import LadybugGraph, resolve_ladybug_path
|
|
27
27
|
from mcp.server.fastmcp import FastMCP
|
|
28
28
|
from pydantic import BaseModel, Field
|
|
29
|
-
|
|
29
|
+
# NOTE: search_lancedb.TABLES is imported lazily in list_code_index_tables_payload() — it
|
|
30
|
+
# pulls lancedb/torch and is unavailable on graph-only installs (macOS Intel).
|
|
30
31
|
|
|
31
32
|
_COCOINDEX_TARGET = "java_index_flow_lancedb.py:JavaCodeIndexLance"
|
|
32
33
|
_INSTRUCTIONS = (
|
|
@@ -296,12 +297,19 @@ def _graph_meta_output() -> GraphMetaOutput:
|
|
|
296
297
|
|
|
297
298
|
|
|
298
299
|
def list_code_index_tables_payload() -> IndexInfoOutput:
|
|
300
|
+
try:
|
|
301
|
+
from search_lancedb import TABLES
|
|
302
|
+
|
|
303
|
+
tables = dict(TABLES)
|
|
304
|
+
except ImportError:
|
|
305
|
+
# Graph-only install (no lancedb): no Lance vector tables exist.
|
|
306
|
+
tables = {}
|
|
299
307
|
return IndexInfoOutput(
|
|
300
308
|
lancedb_uri=_resolve_lancedb_uri(),
|
|
301
309
|
embedding_model=resolved_sbert_model_for_process_env(SBERT_MODEL),
|
|
302
310
|
project_root=str(_project_root()),
|
|
303
311
|
cocoindex_target=_COCOINDEX_TARGET,
|
|
304
|
-
tables=
|
|
312
|
+
tables=tables,
|
|
305
313
|
graph=_graph_meta_output(),
|
|
306
314
|
)
|
|
307
315
|
|
|
@@ -499,11 +507,12 @@ def create_mcp_server() -> FastMCP:
|
|
|
499
507
|
"Ranked chunk retrieval over content tables (java/sql/yaml); `query` is opaque text (natural language or code "
|
|
500
508
|
"fragments) and results are score-ranked, not boolean-matched. For graph-structured listing "
|
|
501
509
|
"(symbols/routes/clients/producers) use `find`, not `search`. Optional `filter` uses the same NodeFilter "
|
|
502
|
-
"schema as `find` but only **symbol-applicable** fields apply — others return success=false.
|
|
503
|
-
"
|
|
510
|
+
"schema as `find` but only **symbol-applicable** fields apply — others return success=false. Substring "
|
|
511
|
+
"fields match literally (no `*`/`?` metacharacters)—use ranked `query` text for fuzzy discovery. There is **no** "
|
|
504
512
|
"structured DSL inside `query`; structured predicates belong in `find`. "
|
|
505
|
-
"For identifier-shaped lookups (FQN, id
|
|
513
|
+
"For identifier-shaped lookups (FQN, id, route/client identifiers, …), use `resolve` first; "
|
|
506
514
|
"use `search` for natural-language or ranked fuzzy discovery. "
|
|
515
|
+
"Set `explain=true` to include score breakdown per hit. "
|
|
507
516
|
"Successful responses echo `limit`/`offset`."
|
|
508
517
|
),
|
|
509
518
|
)
|
|
@@ -530,6 +539,14 @@ def create_mcp_server() -> FastMCP:
|
|
|
530
539
|
"predicate. Unknown keys or populated fields not applicable to symbols return success=false."
|
|
531
540
|
),
|
|
532
541
|
),
|
|
542
|
+
explain: bool = Field(
|
|
543
|
+
default=False,
|
|
544
|
+
description="If true, include score_components in each SearchHit (breakdown of distance/rrf, role, symbol, import_penalty).",
|
|
545
|
+
),
|
|
546
|
+
chunks: bool = Field(
|
|
547
|
+
default=False,
|
|
548
|
+
description="If true, show every chunk (default collapses to one row per symbol/type).",
|
|
549
|
+
),
|
|
533
550
|
) -> mcp_v2.SearchOutput:
|
|
534
551
|
scoped_filter = _scope_manager.apply_auto_scope(filter) if _scope_manager else filter
|
|
535
552
|
return await asyncio.to_thread(
|
|
@@ -541,20 +558,22 @@ def create_mcp_server() -> FastMCP:
|
|
|
541
558
|
offset,
|
|
542
559
|
path_contains,
|
|
543
560
|
scoped_filter,
|
|
561
|
+
explain,
|
|
544
562
|
None,
|
|
563
|
+
not chunks, # dedup=True by default; chunks=True opts out
|
|
545
564
|
)
|
|
546
565
|
|
|
547
566
|
@mcp.tool(
|
|
548
567
|
name="find",
|
|
549
568
|
description=(
|
|
550
569
|
"Exact structured listing for one node kind. Per-kind applicable fields: **symbol** — "
|
|
551
|
-
"microservice, module, role, exclude_roles, annotation, capability,
|
|
552
|
-
"**route** — microservice, module, http_method,
|
|
553
|
-
"source_layer, client_kind, target_service,
|
|
554
|
-
"module, source_layer, producer_kind,
|
|
570
|
+
"microservice, module, role, exclude_roles, annotation, capability, fqn_contains, symbol_kind, symbol_kinds; "
|
|
571
|
+
"**route** — microservice, module, http_method, path_contains, framework; **client** — microservice, module, "
|
|
572
|
+
"source_layer, client_kind, target_service, target_path_contains, http_method; **producer** — microservice, "
|
|
573
|
+
"module, source_layer, producer_kind, topic_contains. "
|
|
555
574
|
"`role` is singular and `exclude_roles` plural; `capability` is a functional tag assigned during indexing. "
|
|
556
|
-
"`
|
|
557
|
-
"
|
|
575
|
+
"`fqn_contains` is a substring predicate — for exact FQN or id lookup use `resolve`/`describe`. "
|
|
576
|
+
"Substring fields match literally (Cypher `CONTAINS`); no wildcard metacharacters. An empty filter (`{}`) or `filter=None` means no predicate (all nodes of "
|
|
558
577
|
"that kind; use pagination). Unknown keys or inapplicable populated fields return success=false. "
|
|
559
578
|
"Successful responses echo `limit`/`offset`."
|
|
560
579
|
),
|
|
@@ -620,7 +639,7 @@ def create_mcp_server() -> FastMCP:
|
|
|
620
639
|
"`direction` and `edge_types` have no defaults; an empty `edge_types` fails. The CALLS-only features — "
|
|
621
640
|
"`edge_filter`, `include_unresolved`, `dedup_calls` — each require `edge_types=['CALLS']`; `edge_filter` and "
|
|
622
641
|
"`include_unresolved` are mutually exclusive. Violating a precondition (wrong CALLS context, composed/override "
|
|
623
|
-
"keys on an ineligible origin or with `direction='in'`,
|
|
642
|
+
"keys on an ineligible origin or with `direction='in'`, unknown filter keys) returns "
|
|
624
643
|
"success=false with a message; `dedup_calls` with other edge_types is a silent no-op. "
|
|
625
644
|
"Optional `filter` applies to each neighbor endpoint row; populated fields must be applicable to that "
|
|
626
645
|
"neighbor's kind—mixed-kind result sets fail on the first inapplicable neighbor (per-neighbor strict frame). "
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
ast_java.py,sha256=Paee3ZV9G5iy8LqfkVq0Ah_1fV0k632oS5JPkiWzwB8,99206
|
|
2
|
-
brownfield_events.py,sha256=yxXkKDgMb3VPtaiakGzncHM_EGnda8xIue6w90yYp8s,2055
|
|
3
|
-
build_ast_graph.py,sha256=jubb9Ex_6B3ktsInqNkk-EksBtQjofoFhE92lmHr308,169659
|
|
4
|
-
chunk_heuristics.py,sha256=aQk2NOKxzUdqoUAJUO3G3LE0MN_bYZWNLQ0tkmj5uts,1813
|
|
5
|
-
graph_enrich.py,sha256=W_OQK7YRU1K8wi-vfrxZWUd-EErTqWx840UBrhVpNsM,62788
|
|
6
|
-
index_common.py,sha256=HT6FKHFJ084eFvd3fR1j8z8gf4eWoPHVW8GXLpw464I,285
|
|
7
|
-
java_index_flow_lancedb.py,sha256=JHdRWDZoZ3wnxi8NNG2ck8zEmSALHB2UVB1N8TSvlmg,24109
|
|
8
|
-
java_index_v1_common.py,sha256=nF1KrSqboF_RRvWerG9knRRFmWwsrG_CvhgnsoZ8KqA,1154
|
|
9
|
-
java_ontology.py,sha256=71bCLDNvMy0SpZPzSR5apJ0qJXNd6y5ggkLdBEw_PFo,16682
|
|
10
|
-
ladybug_queries.py,sha256=7vSP7WsUKQYXHFenBMlCdpUFed39h3oul-WRkf55YVc,90330
|
|
11
|
-
mcp_hints.py,sha256=3swh05LSiWur3tm3-yssndBsLxIxFhy501kBtJI8jJ0,42509
|
|
12
|
-
mcp_v2.py,sha256=S8PiVGDlyI7cvTmeMdQobhKUxWqKoY2YxXXr4pu9lQI,80348
|
|
13
|
-
path_filtering.py,sha256=R--XzI51LXBu5IBKMCnJWbkNr6I5d-SDmltyQQnWco0,17674
|
|
14
|
-
pr_analysis.py,sha256=zrmZZD5yotJtM02Kif6_jgI_oeformOao793akp0N6Y,18394
|
|
15
|
-
search_lancedb.py,sha256=ga_qySeCzA6hCibxUPXpCbTxW9mCjTdwirMhMhfNCz4,36801
|
|
16
|
-
server.py,sha256=DcJwocSknBy0vwsUvYiC5hr-hrD_rRT-u9_DmuRTC9k,35035
|
|
17
|
-
java_codebase_rag/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
18
|
-
java_codebase_rag/_fdlimit.py,sha256=WroFdfSNbcriKok6q8znTf74dqlznxea_1Fd5bHl_3o,1930
|
|
19
|
-
java_codebase_rag/cli.py,sha256=zMZcjVKRgfv7VpTb0h1vjGGzPXY4NT2Uqyz77uysc0c,40085
|
|
20
|
-
java_codebase_rag/cli_format.py,sha256=CT7-xdwZ0bMCdP68_UOwkvm-mnLluU3LutlM-mDNk60,1839
|
|
21
|
-
java_codebase_rag/cli_progress.py,sha256=q6Wh97yzLGs1B8UFk_WAKivfQu7Y5RnUUE-T2YHWkIs,3237
|
|
22
|
-
java_codebase_rag/config.py,sha256=bfwYI4R8PU9YV_M4r8-03iaUZ_0TW-qN_NuhIsDXy2M,18769
|
|
23
|
-
java_codebase_rag/installer.py,sha256=sXsHPo24aoDFoTr0D_vYLg0MFdGAV2wdL05FqRaul6E,52861
|
|
24
|
-
java_codebase_rag/lance_optimize.py,sha256=25Rwj7HNO8F-35MxhFK6naqgbjd3H-T0zKb3pXB4H0s,9268
|
|
25
|
-
java_codebase_rag/pipeline.py,sha256=ydNktEGL1YniAjJsr37yKBo_bGV4cN_LTGVTmmrsrZw,14688
|
|
26
|
-
java_codebase_rag/progress.py,sha256=2IxdMALDM0wAQCyJrrfZ975zM_85C-4BfHxf4AtYifE,23212
|
|
27
|
-
java_codebase_rag/install_data/agents/explorer-rag-enhanced.md,sha256=BkdQpBEWqSdvGHgbqMdRb5CWfEiFRJK4Dgqbyal3l6s,14551
|
|
28
|
-
java_codebase_rag/install_data/skills/explore-codebase/SKILL.md,sha256=YkRnrM7Wh5E8raFjAW3RrN2V9-ov8upaGC3UdpSx6U8,12346
|
|
29
|
-
java_codebase_rag-0.6.7.dist-info/licenses/LICENSE,sha256=gxvtiHtuviR_q8ZAjWw-QTcF3DyPzg6ZY-lQrr8OPpw,1068
|
|
30
|
-
java_codebase_rag-0.6.7.dist-info/METADATA,sha256=Hnwc5Zpo53La7PXgldTTlVl87xRGG5KvDTky6ufxyQM,17239
|
|
31
|
-
java_codebase_rag-0.6.7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
32
|
-
java_codebase_rag-0.6.7.dist-info/entry_points.txt,sha256=wsPZwot0Ui4JI3TIgW8LcbN8bNtKFbwQAlHAAJXfYgQ,117
|
|
33
|
-
java_codebase_rag-0.6.7.dist-info/top_level.txt,sha256=syQgi8XPBwY2ws_NZ1uRCxTf_s41NpshwEHNdcdnk3A,245
|
|
34
|
-
java_codebase_rag-0.6.7.dist-info/RECORD,,
|
|
File without changes
|