java-codebase-rag 0.6.0__py3-none-any.whl → 0.6.1__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 CHANGED
@@ -13,6 +13,7 @@ Python with no tree-sitter dependency.
13
13
  from __future__ import annotations
14
14
 
15
15
  import posixpath
16
+ import sys
16
17
  from dataclasses import dataclass, field
17
18
  from functools import lru_cache
18
19
  from typing import Iterable
@@ -1642,9 +1643,17 @@ def _parse_codebase_http_client_annotation(
1642
1643
  pairs, _ = _annotation_kv_nodes(ann, src)
1643
1644
  client_kind = ""
1644
1645
  if "clientKind" in pairs:
1645
- val, _kind = _annotation_value(pairs["clientKind"], src)
1646
- if val and _kind == "enum":
1647
- client_kind = str(val)
1646
+ val, vkind = _annotation_value(pairs["clientKind"], src)
1647
+ if val and vkind == "enum":
1648
+ kind_val = str(val)
1649
+ from java_ontology import VALID_CLIENT_KINDS # deferred: java_ontology imports ast_java
1650
+ if kind_val in VALID_CLIENT_KINDS:
1651
+ client_kind = kind_val
1652
+ else:
1653
+ print(
1654
+ f"[lancedb-mcp] CodebaseHttpClient: invalid clientKind {kind_val!r} — ignored",
1655
+ file=sys.stderr,
1656
+ )
1648
1657
  target_service = ""
1649
1658
  if "targetService" in pairs:
1650
1659
  atoms = _string_value_atoms(pairs["targetService"], src, ctx)
@@ -1714,9 +1723,17 @@ def _parse_codebase_producer_annotation(
1714
1723
  client_kind = "kafka_send"
1715
1724
  kind_node = pairs.get("producerKind") or pairs.get("clientKind")
1716
1725
  if kind_node is not None:
1717
- val, _kind = _annotation_value(kind_node, src)
1718
- if val and _kind == "enum":
1719
- client_kind = str(val)
1726
+ val, vkind = _annotation_value(kind_node, src)
1727
+ if val and vkind == "enum":
1728
+ kind_val = str(val)
1729
+ from java_ontology import VALID_PRODUCER_KINDS # deferred: java_ontology imports ast_java
1730
+ if kind_val in VALID_PRODUCER_KINDS:
1731
+ client_kind = kind_val
1732
+ else:
1733
+ print(
1734
+ f"[lancedb-mcp] CodebaseProducer: invalid producerKind {kind_val!r} — ignored",
1735
+ file=sys.stderr,
1736
+ )
1720
1737
  topic = ""
1721
1738
  if "topic" in pairs:
1722
1739
  atoms = _string_value_atoms(pairs["topic"], src, ctx)
build_ast_graph.py CHANGED
@@ -3668,10 +3668,17 @@ def incremental_rebuild(
3668
3668
 
3669
3669
 
3670
3670
  def _init_hash_tracker(source_root: Path, ladybug_path: Path) -> int:
3671
- """Initialize hash tracker for all Java files. Returns number of files hashed."""
3671
+ """Initialize hash tracker for all Java files. Returns number of files hashed.
3672
+
3673
+ Called right after a full graph rebuild (``write_ladybug``), so the store must
3674
+ mirror exactly the files that were just indexed. We deliberately do NOT
3675
+ ``load()`` the existing store: ``update`` re-hashes every current file anyway,
3676
+ and preserving old entries would leave stale hashes for files that no longer
3677
+ exist (deleted or now-ignored). Those ghosts would be re-detected as "removed"
3678
+ on every subsequent ``increment``, sustaining an endless full-rebuild loop.
3679
+ """
3672
3680
  index_dir = ladybug_path.parent
3673
3681
  tracker = FileHashTracker(index_dir)
3674
- tracker.load()
3675
3682
  ignore = LayeredIgnore(source_root)
3676
3683
  all_files: set[str] = set()
3677
3684
  source_root_resolved = source_root.resolve()
@@ -3742,7 +3749,7 @@ def _write_clients_producers_and_calls(conn: ladybug.Connection, tables: GraphTa
3742
3749
 
3743
3750
  # Write declares_client edges
3744
3751
  for row in tables.declares_client_rows:
3745
- source_file = member_by_id.get(row.symbol_id, MemberEntry(kind="", decl=None, parent_id="", parent_fqn="", file_path="", module="", microservice="")).file_path
3752
+ source_file = member_by_id.get(row.symbol_id, MemberEntry(kind="", decl=None, parent_id="", parent_fqn="", file_path="", module="", microservice="", node_id="")).file_path
3746
3753
  conn.execute(_CREATE_DECLARES_CLIENT, {
3747
3754
  "sid": row.symbol_id,
3748
3755
  "cid": row.client_id,
@@ -3753,7 +3760,7 @@ def _write_clients_producers_and_calls(conn: ladybug.Connection, tables: GraphTa
3753
3760
 
3754
3761
  # Write declares_producer edges
3755
3762
  for row in tables.declares_producer_rows:
3756
- source_file = member_by_id.get(row.symbol_id, MemberEntry(kind="", decl=None, parent_id="", parent_fqn="", file_path="", module="", microservice="")).file_path
3763
+ source_file = member_by_id.get(row.symbol_id, MemberEntry(kind="", decl=None, parent_id="", parent_fqn="", file_path="", module="", microservice="", node_id="")).file_path
3757
3764
  conn.execute(_CREATE_DECLARES_PRODUCER, {
3758
3765
  "sid": row.symbol_id,
3759
3766
  "pid": row.producer_id,
@@ -306,9 +306,19 @@ def _pick_bool(
306
306
  def _resolve_index_dir_path(
307
307
  *,
308
308
  source_root: Path,
309
+ config_dir: Path,
309
310
  cli_index_dir: str | None,
310
311
  yaml_dict: dict[str, Any],
311
312
  ) -> tuple[Path, SettingSource]:
313
+ # Bases for relative paths:
314
+ # - YAML ``index_dir`` -> the config file's directory (``config_dir``),
315
+ # the SAME base used for YAML ``source_root``. Paths written in the
316
+ # config file are relative to the file, so both keys stay consistent.
317
+ # - CLI / env ``index_dir`` -> ``source_root`` (unchanged). These are not
318
+ # "in the config file"; preserving the existing base avoids a semantics
319
+ # change for operators who pass ``--index-dir`` on the command line.
320
+ # - Default ``./.java-codebase-rag`` -> ``source_root`` so the index sits
321
+ # beside the Java tree (the layout ``discover_project_root`` anchors on).
312
322
  raw_cli = cli_index_dir.strip() if isinstance(cli_index_dir, str) else None
313
323
  if raw_cli:
314
324
  p = Path(raw_cli).expanduser()
@@ -324,7 +334,7 @@ def _resolve_index_dir_path(
324
334
  idx = yaml_dict.get("index_dir")
325
335
  if isinstance(idx, str) and idx.strip():
326
336
  p = Path(idx.strip()).expanduser()
327
- out = p.resolve() if p.is_absolute() else (source_root / p).resolve()
337
+ out = p.resolve() if p.is_absolute() else (config_dir / p).resolve()
328
338
  return out, "yaml"
329
339
 
330
340
  return (source_root / ".java-codebase-rag").resolve(), "default"
@@ -368,7 +378,7 @@ def resolve_operator_config(
368
378
  root = config_dir
369
379
 
370
380
  index_dir, index_src = _resolve_index_dir_path(
371
- source_root=root, cli_index_dir=cli_index_dir, yaml_dict=yaml_dict
381
+ source_root=root, config_dir=config_dir, cli_index_dir=cli_index_dir, yaml_dict=yaml_dict
372
382
  )
373
383
  model, model_src = _pick_str(
374
384
  cli_val=cli_embedding_model,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: java-codebase-rag
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: MCP server for semantic + structural search over Java codebases
5
5
  Author: HumanBean17
6
6
  License-Expression: MIT
@@ -35,6 +35,7 @@ Requires-Dist: unidiff<1,>=0.7.3
35
35
  Provides-Extra: dev
36
36
  Requires-Dist: pytest>=7; extra == "dev"
37
37
  Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
38
+ Requires-Dist: pytest-xdist>=3; extra == "dev"
38
39
  Requires-Dist: ruff>=0.4; extra == "dev"
39
40
  Dynamic: license-file
40
41
 
@@ -1,33 +1,36 @@
1
- ast_java.py,sha256=TMesuv4SYqzkwfKxf_Pps0KaPLZNZOrhU8mL20bwqeQ,98882
1
+ ast_java.py,sha256=NQgZzstbsMq-PdowoD6r_ixJKxEEFzTP9xUzqDpiXeU,99661
2
2
  brownfield_events.py,sha256=yxXkKDgMb3VPtaiakGzncHM_EGnda8xIue6w90yYp8s,2055
3
- build_ast_graph.py,sha256=GNbjiIAwsXaJQ9Je6gbR-dB9SbnaLThya2pEw3tggQs,152396
3
+ build_ast_graph.py,sha256=OKigswkUmWwUAKXXRNH4zplw2VonIdWUWzVjC-t5roo,152893
4
4
  chunk_heuristics.py,sha256=aQk2NOKxzUdqoUAJUO3G3LE0MN_bYZWNLQ0tkmj5uts,1813
5
5
  graph_enrich.py,sha256=POT4LwSkTsrjUmP67bsm2UezUam70cunuPDYDh-v1Bs,63332
6
6
  index_common.py,sha256=HT6FKHFJ084eFvd3fR1j8z8gf4eWoPHVW8GXLpw464I,285
7
7
  java_index_flow_lancedb.py,sha256=MH9iTNF6HDHDTt5Jn7TOVE5hQ4WUPNt7PlQoh1tuh9o,13212
8
8
  java_index_v1_common.py,sha256=nF1KrSqboF_RRvWerG9knRRFmWwsrG_CvhgnsoZ8KqA,1154
9
- java_ontology.py,sha256=FcnOq1XWhUP03OfnTkRStslqrNyukzUKH7VNuK6Bme4,16425
9
+ java_ontology.py,sha256=71bCLDNvMy0SpZPzSR5apJ0qJXNd6y5ggkLdBEw_PFo,16682
10
+ kuzu_queries.py,sha256=9bQzrU311AOw_BcUp_KSGiZgPVSaLSU7y63XfcT_vqI,90137
10
11
  ladybug_queries.py,sha256=912j9VAYDjcU4ReVorWQ6R4DZl0tteKic-Pqu0jyBS0,90837
11
12
  mcp_hints.py,sha256=3swh05LSiWur3tm3-yssndBsLxIxFhy501kBtJI8jJ0,42509
12
- mcp_v2.py,sha256=64UDrQ27hAQtlz3pFp9A3Xlk95bUjYZ4VBscsyAPCIY,79116
13
+ mcp_v2.py,sha256=o94GJI7j6dLJDIA3R_1ZiQhjzQfMAEW3etdeZYnHOUc,80637
13
14
  path_filtering.py,sha256=-oX16SYLWYwX9pcV1fu3vbVTIhY1GzFflT7J1E2tqPY,17122
14
15
  pr_analysis.py,sha256=3-5L8_G5XupdJsl9RN73Lq-ejPoK11B3m_VzAx2fGG8,18413
15
16
  search_lancedb.py,sha256=scG6HBUrsgIeSWFrGcLcGdhWv1qODOx4JOBMAlLDY_E,36793
16
- server.py,sha256=uGKT0PdM-bVrzIsfbxF6ZuHGcuRMSSlvkJk0e7Ff43Y,30556
17
+ server.py,sha256=Js3XDpV7ThAtj352StH6QdhHutf1D5qUkbR-8k3jO8g,31303
17
18
  java_codebase_rag/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
18
19
  java_codebase_rag/_fdlimit.py,sha256=WroFdfSNbcriKok6q8znTf74dqlznxea_1Fd5bHl_3o,1930
19
20
  java_codebase_rag/cli.py,sha256=a5IFLWAsh77mfLv1Z9OdpvLaYvj4i0KR3_kLtL-ans8,34156
20
21
  java_codebase_rag/cli_format.py,sha256=arU7P9W6Fvm7X_wzR1wJ8EfyxK1rDP_ESEhdA0ub4Mo,2579
21
22
  java_codebase_rag/cli_progress.py,sha256=9jCqEagYOXs32SYVA31_sOCrONvYy7cl1CrdBD2Pg44,3168
22
- java_codebase_rag/config.py,sha256=u4OomvglTWHUmMpcxN8wPRnRGfXVp3qK_GJ5pY96O98,16267
23
+ java_codebase_rag/config.py,sha256=Gn3LgxkTOtAvsL-3U2Xn7atOIhyOT2aGmY8SBBTLoQg,16975
23
24
  java_codebase_rag/installer.py,sha256=DlBuVVWbHXgcjaQkuXUeT9fNdmk7XZefVT3zzw47k18,45965
24
25
  java_codebase_rag/lance_optimize.py,sha256=MzACYlgwxmkJCK64qQLyIAdizSq5BARqaMYSZONlc1I,6069
25
26
  java_codebase_rag/pipeline.py,sha256=UcgluFAW9Ghnas8u40x45bVic0mQv6rjzcliDKsnYJI,11936
26
27
  java_codebase_rag/install_data/agents/explorer-rag-enhanced.md,sha256=APl9d-No12qZNZLjU7mwNRwxHIgnT3ZtQZiD4clWlyU,14413
27
28
  java_codebase_rag/install_data/skills/explore-codebase/SKILL.md,sha256=pIM-Xdwq_fXkhhBJCdb-fA2nes5c_mMPcdUXb7Adyxo,12040
28
- java_codebase_rag-0.6.0.dist-info/licenses/LICENSE,sha256=gxvtiHtuviR_q8ZAjWw-QTcF3DyPzg6ZY-lQrr8OPpw,1068
29
- java_codebase_rag-0.6.0.dist-info/METADATA,sha256=GoMO3zFTb98w4rVV5SMXpcLK-irlDs7aUH0wBGlv5cQ,16887
30
- java_codebase_rag-0.6.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
31
- java_codebase_rag-0.6.0.dist-info/entry_points.txt,sha256=mVVQJa0n73OWfhHXYCDoPRrWin_LJhH2Rn0CkJ2iax4,101
32
- java_codebase_rag-0.6.0.dist-info/top_level.txt,sha256=syQgi8XPBwY2ws_NZ1uRCxTf_s41NpshwEHNdcdnk3A,245
33
- java_codebase_rag-0.6.0.dist-info/RECORD,,
29
+ java_codebase_rag-0.6.1.dist-info/licenses/LICENSE,sha256=gxvtiHtuviR_q8ZAjWw-QTcF3DyPzg6ZY-lQrr8OPpw,1068
30
+ user_rag/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
31
+ user_rag/cli.py,sha256=TVcyfzwvmdYXJW6KrEYTKMHm7z2JSXMmz2uB-8kkjxY,5604
32
+ java_codebase_rag-0.6.1.dist-info/METADATA,sha256=aPiLbGD8xE-P3B_RI9gx7VuqrTd-VUriZ--ZPYNK02I,16934
33
+ java_codebase_rag-0.6.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
34
+ java_codebase_rag-0.6.1.dist-info/entry_points.txt,sha256=mVVQJa0n73OWfhHXYCDoPRrWin_LJhH2Rn0CkJ2iax4,101
35
+ java_codebase_rag-0.6.1.dist-info/top_level.txt,sha256=syQgi8XPBwY2ws_NZ1uRCxTf_s41NpshwEHNdcdnk3A,245
36
+ java_codebase_rag-0.6.1.dist-info/RECORD,,
java_ontology.py CHANGED
@@ -15,7 +15,10 @@ from ast_java import (
15
15
  _TYPE_ANN_TO_CAPABILITY,
16
16
  )
17
17
 
18
- # Roles: Spring stereotype values plus DTO from `infer_role_for_type`.
18
+ # Roles assignable by indexing: Spring stereotype values plus DTO. ``OTHER`` is the
19
+ # built-in inference fallback (ast_java.infer_role when nothing matches) and is
20
+ # deliberately excluded here — it is a read-side value (the mcp_v2 ``Role`` enum
21
+ # includes it) but not a role a user may set via @CodebaseRole / role_overrides.
19
22
  VALID_ROLES: frozenset[str] = frozenset((*ROLE_ANNOTATIONS.values(), "DTO"))
20
23
 
21
24
  VALID_CAPABILITIES: frozenset[str] = frozenset(