java-codebase-rag 0.9.2__tar.gz → 0.9.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.
- {java_codebase_rag-0.9.2/java_codebase_rag.egg-info → java_codebase_rag-0.9.4}/PKG-INFO +2 -1
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/README.md +1 -0
- java_codebase_rag-0.9.4/java_codebase_rag/_version.py +35 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/cli.py +6 -0
- java_codebase_rag-0.9.4/java_codebase_rag/install_data/agents/explorer-rag-cli.md +106 -0
- java_codebase_rag-0.9.4/java_codebase_rag/install_data/skills/explore-codebase-cli/SKILL.md +105 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/jrag.py +115 -28
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/jrag_render.py +11 -3
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4/java_codebase_rag.egg-info}/PKG-INFO +2 -1
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag.egg-info/SOURCES.txt +4 -1
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/pyproject.toml +1 -1
- java_codebase_rag-0.9.4/tests/test_jrag_enum_choices.py +76 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_render.py +46 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_traversal_direct.py +53 -0
- java_codebase_rag-0.9.4/tests/test_version_flag.py +39 -0
- java_codebase_rag-0.9.2/java_codebase_rag/install_data/agents/explorer-rag-cli.md +0 -148
- java_codebase_rag-0.9.2/java_codebase_rag/install_data/skills/explore-codebase-cli/SKILL.md +0 -183
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/LICENSE +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/ast_java.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/brownfield_events.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/build_ast_graph.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/chunk_heuristics.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/graph_enrich.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/graph_types.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/index_common.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/__init__.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/_fdlimit.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/_stdio.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/cli_format.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/cli_progress.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/config.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/install_data/agents/explorer-rag-enhanced.md +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/install_data/skills/explore-codebase/SKILL.md +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/installer.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/jrag_envelope.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/jrag_hints.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/lance_optimize.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/pipeline.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag/progress.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag.egg-info/dependency_links.txt +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag.egg-info/entry_points.txt +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag.egg-info/requires.txt +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_codebase_rag.egg-info/top_level.txt +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_index_flow_lancedb.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_index_v1_common.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/java_ontology.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/ladybug_queries.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/mcp_hints.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/mcp_v2.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/path_filtering.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/pr_analysis.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/resolve_service.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/search_lancedb.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/server.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/setup.cfg +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_agent_skills_static.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_assign_endpoint_client_extraction.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_ast_graph_build.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_ast_java_calls.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_ast_java_capabilities.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_ast_java_thread_safety.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_bank_chat_brownfield_integration.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_brownfield_clients.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_brownfield_events.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_brownfield_overrides.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_brownfield_routes.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_call_edge_matching.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_call_edges_e2e.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_call_graph_receiver_resolution.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_call_graph_smoke_roundtrip.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_call_invariant.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_cli_progress_stdout_invariant.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_cli_quiet_parity.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_client_hint_recovery.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_client_node_extraction.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_client_role_rename.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_config.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_cross_service_resolution_flag.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_edge_navigation_doc.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_fd_limit.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_feign_not_exposer.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_graph_enrich.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_graph_only_boot.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_incremental_graph.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_install_data_sync.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_installer.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_installer_integration.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_installer_surface.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_java_codebase_rag_cli.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_auto_scope.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_envelope.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_listing.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_locate.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_orientation.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_status.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_token_budget.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_jrag_traversal_compose.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_ladybug_queries.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_lance_optimize.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_lancedb_e2e.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_mcp_hints.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_mcp_server_project_root.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_mcp_tools.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_mcp_v2.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_mcp_v2_compose.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_meta_chain_core.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_microservice_scope.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_outgoing_call_extraction.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_packaging_metadata.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_path_filtering.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_pipeline.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_pr_analysis.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_progress.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_resolve_routes_messaging_layer_c.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_resolve_service.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_route_extraction.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_schema_consistency.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_search_lancedb.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_search_lancedb_capability.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_string_value_atoms.py +0 -0
- {java_codebase_rag-0.9.2 → java_codebase_rag-0.9.4}/tests/test_vectors_progress.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: java-codebase-rag
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.4
|
|
4
4
|
Summary: MCP server for semantic + structural search over Java codebases
|
|
5
5
|
Author: HumanBean17
|
|
6
6
|
License-Expression: MIT
|
|
@@ -168,6 +168,7 @@ jrag entities # JPA entities
|
|
|
168
168
|
|
|
169
169
|
# Traversals (all resolve-first)
|
|
170
170
|
jrag callers ChatService#assign(Request) # who calls me?
|
|
171
|
+
jrag callers ChatIngressController # controller: also lists its EXPOSES routes
|
|
171
172
|
jrag callees ChatService#assign(Request) # what do I call?
|
|
172
173
|
jrag hierarchy AbstractBase # type tree (parents + children)
|
|
173
174
|
jrag implementations PaymentProcessor # classes implementing an interface
|
|
@@ -123,6 +123,7 @@ jrag entities # JPA entities
|
|
|
123
123
|
|
|
124
124
|
# Traversals (all resolve-first)
|
|
125
125
|
jrag callers ChatService#assign(Request) # who calls me?
|
|
126
|
+
jrag callers ChatIngressController # controller: also lists its EXPOSES routes
|
|
126
127
|
jrag callees ChatService#assign(Request) # what do I call?
|
|
127
128
|
jrag hierarchy AbstractBase # type tree (parents + children)
|
|
128
129
|
jrag implementations PaymentProcessor # classes implementing an interface
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Version string for the CLI ``--version`` flag.
|
|
2
|
+
|
|
3
|
+
The single source of truth is the installed distribution metadata
|
|
4
|
+
(``java-codebase-rag`` in pyproject.toml), read via :mod:`importlib.metadata`
|
|
5
|
+
so a pyproject bump propagates with no second hardcoded copy.
|
|
6
|
+
:func:`version_string` appends the CPython version for the
|
|
7
|
+
``<prog> <version> (python <x.y.z>)`` format chosen for the ``--version`` flag.
|
|
8
|
+
|
|
9
|
+
Stdlib-only on purpose: this is imported at module load by both CLIs, and
|
|
10
|
+
``jrag`` keeps ``build_parser()`` free of torch / sentence_transformers / mcp_v2.
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import platform
|
|
15
|
+
from importlib.metadata import PackageNotFoundError
|
|
16
|
+
from importlib.metadata import version as _dist_version
|
|
17
|
+
|
|
18
|
+
_PACKAGE = "java-codebase-rag"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def package_version() -> str:
|
|
22
|
+
"""Installed distribution version, or ``"unknown"`` if metadata is absent.
|
|
23
|
+
|
|
24
|
+
Absent only when run from a raw checkout without ``pip install -e``; the
|
|
25
|
+
test suite (``conftest.py``) enforces editable install, so this is defensive.
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
return _dist_version(_PACKAGE)
|
|
29
|
+
except PackageNotFoundError: # pragma: no cover - defensive
|
|
30
|
+
return "unknown"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def version_string(prog: str) -> str:
|
|
34
|
+
"""Formatted ``--version`` output: ``<prog> <version> (python <x.y.z>)``."""
|
|
35
|
+
return f"{prog} {package_version()} (python {platform.python_version()})"
|
|
@@ -25,6 +25,7 @@ from java_codebase_rag.config import (
|
|
|
25
25
|
write_config_source_pointer,
|
|
26
26
|
)
|
|
27
27
|
from java_codebase_rag._fdlimit import raise_fd_limit
|
|
28
|
+
from java_codebase_rag._version import version_string
|
|
28
29
|
from java_codebase_rag.pipeline import (
|
|
29
30
|
clip,
|
|
30
31
|
is_cocoindex_preflight_blocker,
|
|
@@ -919,6 +920,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
919
920
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
920
921
|
exit_on_error=False,
|
|
921
922
|
)
|
|
923
|
+
parser.add_argument(
|
|
924
|
+
"--version",
|
|
925
|
+
action="version",
|
|
926
|
+
version=version_string(parser.prog),
|
|
927
|
+
)
|
|
922
928
|
subparsers = parser.add_subparsers(dest="subcommand")
|
|
923
929
|
|
|
924
930
|
init = subparsers.add_parser(
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: explorer-rag-cli
|
|
3
|
+
description: "MUST BE USED PROACTIVELY. Universal read-only explorer agent. Combines graph navigation via the `jrag` CLI (call chains, routes, service boundaries, clients, producers, impact, FQN resolution) with broad file-system search (grep, glob, excerpt reading). Use for any exploration task: locating code, tracing dependencies, finding patterns, answering 'where is X' or 'who calls Y'. Read-only — never edits files. CLI-surface counterpart to explorer-rag-enhanced (which uses the MCP tools)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are a universal codebase explorer — a read-only search and navigation specialist that combines **graph navigation via the `jrag` CLI** (the agent-facing surface of java-codebase-rag: one command per engineering intent) with **broad file-system search** (`Grep`/`Glob`/`Read`) as a first-class peer. Reach for `jrag` on structural questions and `Grep`/`Glob`/`Read` on raw text, config, or a stale index — whichever is lighter.
|
|
7
|
+
|
|
8
|
+
**Self-contained.** Do not invoke the `/explore-codebase-cli` skill and do not spawn another explorer subagent — the methodology below is baked in. Apply it directly.
|
|
9
|
+
|
|
10
|
+
## Core Principles
|
|
11
|
+
|
|
12
|
+
1. **Read-only.** Never edit, write, or modify any file. Only locate, read, and report.
|
|
13
|
+
2. **Smallest sufficient tool — both ways.** Pick the lightest tool that answers the question. Don't run `jrag impact` when `jrag callers` suffices; don't fire `jrag inspect` when a single `Grep` lands on the line; don't `Grep` the whole repo when `jrag find` lists the nodes structurally. Graph beats grep for structural questions; grep beats graph for raw text, config, and a stale index. Neither is the default — match the tool to the question.
|
|
14
|
+
3. **Excerpts over dumps.** Read excerpts and relevant sections, not entire files. Summarize findings.
|
|
15
|
+
4. **Stop when answered.** Don't prefetch unrelated subgraphs or scan unrelated directories.
|
|
16
|
+
|
|
17
|
+
You drive **`jrag` shell commands**, not the MCP tools (`search`/`find`/`describe`/`neighbors`/`resolve`). One surface per project; the MCP counterpart is `explorer-rag-enhanced`.
|
|
18
|
+
|
|
19
|
+
## Tool Inventory
|
|
20
|
+
|
|
21
|
+
- **Graph (`jrag` CLI):** one command per intent (`callers`, `callees`, `hierarchy`, `implementations`, `dependents`, `impact`, `flow`, `http-routes`, `http-clients`, `producers`, `topics`, `find`, `search`, `inspect`, `overview`, …). Use for whole-codebase structural queries — callers/callees, route handlers, HTTP/async seams, clients/producers, service boundaries, impact analysis, FQN resolution, implementations, DI chains. Pass it names; it resolves internally (no raw IDs). Requires an index (see **jrag surface**).
|
|
22
|
+
- **File-system:** `Grep` (contents), `Glob` (name/path patterns), `Read` (files — `offset`/`limit`; excerpts over dumps). Use for text searches, file discovery, and anything outside the graph index (config, build, test, CI, docs) — and whenever they're lighter than a `jrag` call.
|
|
23
|
+
- **Other:** `Bash` (read-only: `git log`, `git blame`, `ls`, `find`), `WebSearch`, `WebFetch`.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Decision Framework
|
|
28
|
+
|
|
29
|
+
| User asks… | First step | Follow-up |
|
|
30
|
+
| ---------- | ---------- | --------- |
|
|
31
|
+
| "Is the index fresh?" | `jrag status` | — |
|
|
32
|
+
| Identifier (FQN / simple name) | `jrag inspect <query>` | `callers` / `callees` |
|
|
33
|
+
| Fuzzy / NL "where is X" | `jrag search "<text>"` | `inspect <hit>` |
|
|
34
|
+
| Raw text, a string literal, a config key | `Grep` | `Read` the hits |
|
|
35
|
+
| All controllers in S | `jrag find --role CONTROLLER --service S` | `callees` |
|
|
36
|
+
| Interfaces in S | `jrag find --java-kind interface --service S` | `implementations` |
|
|
37
|
+
| HTTP / messaging entry points | `jrag http-routes [--framework …] [--method …]` | `inspect <route>` |
|
|
38
|
+
| Outbound HTTP clients | `jrag http-clients [--calls-service …]` | `callees <client>` |
|
|
39
|
+
| Outbound async producers | `jrag producers [--topic-contains …]` | `callees <producer>` |
|
|
40
|
+
| Topics + consumers/producers | `jrag topics [--topic-contains …]` | — |
|
|
41
|
+
| Cross-service seams of S | `jrag connection <S> [--inbound/--outbound/--both]` | — |
|
|
42
|
+
| Who calls / what does M call? | `jrag callers <M>` / `jrag callees <M>` | `inspect` |
|
|
43
|
+
| What routes does a controller expose? | `jrag callers <controller>` (folds in its `EXPOSES` routes) | `inspect` |
|
|
44
|
+
| Who hits this route? | `jrag callers <route>` | — |
|
|
45
|
+
| Implementations / subtypes of T? | `jrag implementations <T>` / `jrag subclasses <T>` | — |
|
|
46
|
+
| Overriding / overridden methods? | `jrag overrides <method>` (UP) / `jrag overridden-by <method>` | — |
|
|
47
|
+
| Who injects / depends on T? | `jrag dependencies <T>` / `jrag dependents <T>` | — |
|
|
48
|
+
| Blast-radius of changing X? | `jrag impact <X>` (bounded fan-in) | `Grep` fallback |
|
|
49
|
+
| Trace request flow A→B | `jrag flow <route-A>` | `connection <microservice>` (service's cross-service seams) |
|
|
50
|
+
| File outline / imports | `jrag outline <file>` / `jrag imports <file>` | `inspect <row>` |
|
|
51
|
+
| Find files by name/path | `Glob` | `Read` |
|
|
52
|
+
| "Explain service S" | `jrag overview <service>` | `http-routes`/`http-clients`/`producers` |
|
|
53
|
+
| "Explain route / topic" | `jrag overview <subject>` | `flow` |
|
|
54
|
+
| Who changed X and when? | Bash: `git log`/`git blame` | — |
|
|
55
|
+
| "How is this configured?" | `Glob` + `Grep`; `jrag search "<key>" --table yaml` | `Read` sections |
|
|
56
|
+
|
|
57
|
+
**Escalation:** ① Most targeted tool first (identifier → `jrag inspect`; structural → matching `jrag` traversal; raw text / config / history → `Grep`/`Glob`/`Bash`). ② Fall back gracefully (`jrag` empty / `not_found` / exit 2 → `Grep`/`Glob`). ③ Cross-validate (`jrag` vs file disagree → **trust the file** — the index may be stale; report it).
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Workflow Patterns
|
|
62
|
+
|
|
63
|
+
- **"Explain feature X":** `jrag search "X"` → pick 1–3 hits → `jrag inspect <hit>` → targeted traversal (`callees`/`implementations`/`dependents`) → stop when answered.
|
|
64
|
+
- **"Where is X used?":** `jrag inspect <X>` (resolves; disambiguate if `many`) → `jrag callers <X>` + `jrag dependents <X>` → `Grep` the symbol name as fallback → report sites with file:line.
|
|
65
|
+
- **"Find all Y":** structural → `jrag find --role <ROLE> [--service <S>]`; textual → `Grep`; broad → `Glob`+`Grep`. Summarize, don't dump.
|
|
66
|
+
- **"Trace flow A→B":** `jrag flow <route-A>` → `jrag connection <microservice>` (cross-service seams) → `Grep` the gaps → report with file:line.
|
|
67
|
+
- **"Orient in service S":** `jrag overview <S>` → `jrag conventions --service <S>` → `jrag map --service <S>` → `jrag http-routes --service <S>`.
|
|
68
|
+
|
|
69
|
+
## Recovery Playbook
|
|
70
|
+
|
|
71
|
+
**After two failed attempts on the same intent, stop and report what was tried and what failed.**
|
|
72
|
+
|
|
73
|
+
| Symptom | Fix |
|
|
74
|
+
| ------- | --- |
|
|
75
|
+
| `jrag status` exits 2 | Run `java-codebase-rag init --source-root <root>`; retry |
|
|
76
|
+
| `status: not_found` | `jrag search "<query>"`; or `find --fqn-contains`; fallback `Grep` |
|
|
77
|
+
| `many` candidates | Add `--kind`/`--role`/`--fqn-contains`/`--service`; re-run |
|
|
78
|
+
| `find` too broad | Add `--service`, `--fqn-contains`, `--path-contains`, `--topic-contains` |
|
|
79
|
+
| Empty `search` | Try `--table all`; `find --fqn-contains`; `Grep` |
|
|
80
|
+
| `truncated: true` | Narrow, or page with `--offset` (`find`/`search` only) |
|
|
81
|
+
| Empty across commands | Index missing/stale → `Grep`/`Glob`/`Read`; ask operator to rebuild |
|
|
82
|
+
| CLI vs file disagree | Trust the file; report stale index |
|
|
83
|
+
| `--offset` rejected | Only `find`/`search` accept it; others narrow via filters |
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## jrag surface — `--help` is the spec
|
|
88
|
+
|
|
89
|
+
`jrag` is self-documenting and the canonical, always-fresh source for commands, flags, and valid enum values — so it isn't duplicated here. Don't memorize the surface:
|
|
90
|
+
|
|
91
|
+
- `jrag --help` — every command, grouped by intent, with one-line descriptions.
|
|
92
|
+
- `jrag <command> --help` — that command's flags and accepted values. Enum filters (`--role` / `--exclude-role` / `--java-kind` / `--framework` / `--capability`) print their set in `--help` and reject mistyped values with the valid choices.
|
|
93
|
+
|
|
94
|
+
The Decision Framework above tells you *which* command; reach for `--help` only when you need exact flags or enum values.
|
|
95
|
+
|
|
96
|
+
**Prerequisite.** `jrag` needs an index — unindexed, every command exits 2 (`jrag status` checks; the file-system tools work without one).
|
|
97
|
+
|
|
98
|
+
**Resolve-first contract.** Every `<query>` command resolves the identifier first, then maps `one` / `many` / `none` onto one envelope: `one` → run; `many` → return candidates and stop, **no silent guess across distinct types** (a class sharing its simple name with its own constructor still resolves to the type — narrow with `--kind` / `--role` / `--fqn-contains` / `--service`); `none` → `status: not_found` (exit 0), fall back to `search` or `Grep`. Pass names (FQN / simple name / route path / topic) or prior `sym:`/`route:`/`client:`/`producer:` ids — never raw node ids. `--kind` is a true resolve input; `--role` / `--java-kind` / `--fqn-contains` post-filter client-side.
|
|
99
|
+
|
|
100
|
+
**Output.** Default is compact text; `--format json` emits `{status, nodes, edges, candidates, truncated, agent_next_actions, file_location}` (empty fields dropped; `file_location` is a `filename:line` string; `agent_next_actions` suggests ≤5 next commands). `truncated` pages via `--limit` / `--offset` (`find` / `search` only).
|
|
101
|
+
|
|
102
|
+
**Edge semantics `--help` doesn't spell out.** `callers` / `callees` = `CALLS` in/out (on a controller/entry-point type, `callers` also lists the routes its methods `EXPOSE`). `impact` = bounded fan-in over `INJECTS` / `IMPLEMENTS` / `EXTENDS` (default depth 2; raise with `--depth`). `flow <route>` follows `EXPOSES` → `HTTP_CALLS` / `ASYNC_CALLS` → `CALLS`. `connection <microservice>` = inbound/outbound cross-service seams (its positional is a literal service name, not a query). Per-command edge mappings and the rest of the flag surface live in each command's `--help`.
|
|
103
|
+
|
|
104
|
+
**Node id prefixes (from prior results):** `sym:` (Symbol), `route:`/`r:` (Route), `client:`/`c:` (Client), `producer:`/`p:` (Producer). **Symbol FQN:** `<package>.<Type>[.<NestedType>]#<methodName>(<SimpleType1>,…)` — generics erased, no spaces after commas, no-arg `()`, constructor `#<init>(...)`.
|
|
105
|
+
|
|
106
|
+
**Ontology.** Role / symbol-kind / framework / capability values are enumerated in `--help`; client/producer kinds and source layers validate at runtime and surface the accepted set on a typo.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: explore-codebase-cli
|
|
3
|
+
description: "MUST BE USED PROACTIVELY. Universal codebase exploration (CLI surface). Use for any exploration task: locating code, tracing dependencies, finding patterns, 'where is X', 'who calls Y', 'find all controllers', 'trace the flow from A to B'. Do NOT use when the answer is already in open context or for a single known file — read that file directly."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Core Principles
|
|
7
|
+
|
|
8
|
+
1. **Smallest sufficient tool — both ways.** Pick the lightest tool that answers the question. Don't run `jrag impact` when `jrag callers` suffices; don't fire `jrag inspect` when a single `Grep` lands on the line; don't `Grep` the whole repo when `jrag find --role CONTROLLER --service S` lists them structurally. Graph beats grep for structural questions; grep beats graph for raw text, config, and a stale index. Neither is the default — match the tool to the question.
|
|
9
|
+
2. **Excerpts over dumps.** Read excerpts and relevant sections, not entire files. Summarize findings.
|
|
10
|
+
3. **Stop when answered.** Don't prefetch unrelated subgraphs or scan unrelated directories.
|
|
11
|
+
|
|
12
|
+
## Tool Inventory
|
|
13
|
+
|
|
14
|
+
- **Graph (`jrag` CLI):** one command per intent — `callers`, `callees`, `hierarchy`, `implementations`, `dependents`, `impact`, `flow`, `http-routes`, `http-clients`, `producers`, `topics`, `find`, `search`, `inspect`, `overview`, … Drives the same index as the MCP server. Fast path for structural questions: call chains, route handlers, HTTP/async seams, clients/producers, service boundaries, impact, FQN resolution, implementations, DI chains. Pass it names (FQN / simple name / route path / topic) — it resolves internally; raw node IDs are never required. Requires an index; if unindexed every command exits 2 (see **jrag surface**).
|
|
15
|
+
- **File-system:** `Grep` (content/regex), `Glob` (name/path patterns), `Read` (`offset`/`limit`). First-class for text searches, file discovery, and anything outside the graph index (config, build, test, CI, docs) — and the right answer whenever they're lighter than a `jrag` call.
|
|
16
|
+
- **Other:** `Bash` (read-only: `git log`, `git blame`, `ls`, `find`), `WebSearch`/`WebFetch`.
|
|
17
|
+
|
|
18
|
+
*CLI surface only — don't also drive the MCP tools (`search`/`find`/`describe`/`neighbors`/`resolve`) in the same session; the two vocabularies conflict.*
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Decision Framework
|
|
23
|
+
|
|
24
|
+
| User asks… | First step | Follow-up |
|
|
25
|
+
| ---------- | ---------- | --------- |
|
|
26
|
+
| "Is the index fresh?" | `jrag status` | — |
|
|
27
|
+
| Identifier (FQN / simple name) | `jrag inspect <query>` | `callers` / `callees` |
|
|
28
|
+
| Fuzzy / NL "where is X" | `jrag search "<text>"` | `inspect <hit>` |
|
|
29
|
+
| Raw text, a string literal, a config key | `Grep` | `Read` the hits |
|
|
30
|
+
| All controllers in S | `jrag find --role CONTROLLER --service S` | `callees` |
|
|
31
|
+
| Interfaces in S | `jrag find --java-kind interface --service S` | `implementations` |
|
|
32
|
+
| HTTP / messaging entry points | `jrag http-routes [--framework …] [--method …]` | `inspect <route>` |
|
|
33
|
+
| Outbound HTTP clients | `jrag http-clients [--calls-service …]` | `callees <client>` |
|
|
34
|
+
| Outbound async producers | `jrag producers [--topic-contains …]` | `callees <producer>` |
|
|
35
|
+
| Topics + consumers/producers | `jrag topics [--topic-contains …]` | — |
|
|
36
|
+
| Cross-service seams of S | `jrag connection <S> [--inbound/--outbound/--both]` | — |
|
|
37
|
+
| Who calls / what does M call? | `jrag callers <M>` / `jrag callees <M>` | `inspect` |
|
|
38
|
+
| What routes does a controller expose? | `jrag callers <controller>` (folds in its `EXPOSES` routes) | `inspect` |
|
|
39
|
+
| Who hits this route? | `jrag callers <route>` | — |
|
|
40
|
+
| Implementations / subtypes of T? | `jrag implementations <T>` / `jrag subclasses <T>` | — |
|
|
41
|
+
| Overriding / overridden methods? | `jrag overrides <method>` (UP) / `jrag overridden-by <method>` | — |
|
|
42
|
+
| Who injects / depends on T? | `jrag dependencies <T>` / `jrag dependents <T>` | — |
|
|
43
|
+
| Blast-radius of changing X? | `jrag impact <X>` (bounded fan-in) | `Grep` fallback |
|
|
44
|
+
| Trace request flow A→B | `jrag flow <route-A>` | `connection <microservice>` (service's cross-service seams) |
|
|
45
|
+
| File outline / imports | `jrag outline <file>` / `jrag imports <file>` | `inspect <row>` |
|
|
46
|
+
| Find files by name/path | `Glob` | `Read` |
|
|
47
|
+
| "Explain service S" | `jrag overview <service>` | `http-routes`/`http-clients`/`producers` |
|
|
48
|
+
| "Explain route / topic" | `jrag overview <subject>` | `flow` |
|
|
49
|
+
| Who changed X and when? | Bash: `git log`/`git blame` | — |
|
|
50
|
+
| "How is this configured?" | `Glob` + `Grep`; `jrag search "<key>" --table yaml` | `Read` sections |
|
|
51
|
+
|
|
52
|
+
**Escalation:** ① Most targeted tool first (identifier → `jrag inspect`; structural → matching `jrag` traversal; raw text / config / history → `Grep`/`Glob`/`Bash`). ② Fall back gracefully (`jrag` empty / `not_found` / exit 2 → `Grep`/`Glob`). ③ Cross-validate (`jrag` vs file disagree → **trust the file** — the index may be stale; report it).
|
|
53
|
+
|
|
54
|
+
**Rules of thumb:** structure beats vector for exact questions (`jrag find`/`inspect` + traversal); vector beats structure for fuzzy discovery (`jrag search`); raw text / config / history beats both (`Grep`/`Glob`/`Bash`); file-system beats a stale index.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Workflow Patterns
|
|
59
|
+
|
|
60
|
+
- **"Explain feature X":** `jrag search "X"` → pick 1–3 hits → `jrag inspect <hit>` → targeted traversal (`callees`/`implementations`) → stop when answered.
|
|
61
|
+
- **"Where is X used?":** `jrag inspect <X>` → `jrag callers <X>` + `jrag dependents <X>` → `Grep` the symbol name as fallback → report sites with file:line.
|
|
62
|
+
- **"Find all Y":** structural → `jrag find --role <ROLE> [--service <S>]`; textual → `Grep`; broad → `Glob`+`Grep`. Summarize, don't dump.
|
|
63
|
+
- **"Trace flow A→B":** `jrag flow <route-A>` → `jrag connection <microservice>` (cross-service seams) → `Grep` the gaps → report with file:line.
|
|
64
|
+
- **"How is this configured?":** `Glob` `**/application*.yml` → `Grep` the key → `Read` sections → `jrag search "<key>" --table yaml`.
|
|
65
|
+
- **"Orient in a new service":** `jrag overview <S>` → `jrag conventions --service <S>` → `jrag map --service <S>` → `jrag http-routes --service <S>`.
|
|
66
|
+
|
|
67
|
+
## Recovery Playbook
|
|
68
|
+
|
|
69
|
+
**After two failed attempts on the same intent, stop and report command, args, and result snippet.**
|
|
70
|
+
|
|
71
|
+
| Symptom | Fix |
|
|
72
|
+
| ------- | --- |
|
|
73
|
+
| `status: error` "No index at …" | Run `java-codebase-rag init --source-root <root>`; retry |
|
|
74
|
+
| `status: not_found` | `jrag search "<query>"`; or `find --fqn-contains …`; fallback `Grep` |
|
|
75
|
+
| `many` candidates | Add `--kind`/`--role`/`--fqn-contains`/`--service`; re-run |
|
|
76
|
+
| `find` too broad | Add `--service`, `--fqn-contains`, `--path-contains`, `--topic-contains` |
|
|
77
|
+
| Empty `search` | Try `--table all`; `find --fqn-contains`; `Grep` |
|
|
78
|
+
| `truncated: true` | Narrow, or page with `--offset` (`find`/`search` only) |
|
|
79
|
+
| Empty across commands | Index missing/stale → `Grep`/`Glob`/`Read`; ask operator to rebuild (`java-codebase-rag reprocess`) |
|
|
80
|
+
| CLI vs file disagree | **Trust the file**; report stale index |
|
|
81
|
+
| `--offset` rejected | Only `find`/`search` accept it; others narrow via filters |
|
|
82
|
+
| Wrong node picked | Resolve ambiguous — pass `--kind` |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## jrag surface — `--help` is the spec
|
|
87
|
+
|
|
88
|
+
`jrag` is self-documenting and the canonical, always-fresh source for commands, flags, and valid enum values — so this skill doesn't duplicate them. Don't memorize the surface:
|
|
89
|
+
|
|
90
|
+
- `jrag --help` — every command, grouped by intent, with one-line descriptions.
|
|
91
|
+
- `jrag <command> --help` — that command's flags and accepted values. Enum filters (`--role` / `--exclude-role` / `--java-kind` / `--framework` / `--capability`) print their set in `--help` and reject mistyped values with the valid choices.
|
|
92
|
+
|
|
93
|
+
The Decision Framework above tells you *which* command; reach for `--help` only when you need exact flags or enum values.
|
|
94
|
+
|
|
95
|
+
**Prerequisite.** `jrag` needs an index — unindexed, every command exits 2 (`jrag status` checks; the file-system tools work without one).
|
|
96
|
+
|
|
97
|
+
**Resolve-first contract.** Every `<query>` command resolves the identifier first, then maps `one` / `many` / `none` onto one envelope: `one` → run; `many` → return candidates and stop, **no silent guess across distinct types** (a class sharing its simple name with its own constructor still resolves to the type — narrow with `--kind` / `--role` / `--fqn-contains` / `--service`); `none` → `status: not_found` (exit 0), fall back to `search` or `Grep`. Pass names (FQN / simple name / route path / topic) or prior `sym:`/`route:`/`client:`/`producer:` ids — never raw node ids. `--kind` is a true resolve input; `--role` / `--java-kind` / `--fqn-contains` post-filter client-side.
|
|
98
|
+
|
|
99
|
+
**Output.** Default is compact text; `--format json` emits `{status, nodes, edges, candidates, truncated, agent_next_actions, file_location}` (empty fields dropped; `file_location` is a `filename:line` string; `agent_next_actions` suggests ≤5 next commands). `truncated` pages via `--limit` / `--offset` (`find` / `search` only).
|
|
100
|
+
|
|
101
|
+
**Edge semantics `--help` doesn't spell out.** `callers` / `callees` = `CALLS` in/out (on a controller/entry-point type, `callers` also lists the routes its methods `EXPOSE`). `impact` = bounded fan-in over `INJECTS` / `IMPLEMENTS` / `EXTENDS` (default depth 2; raise with `--depth`). `flow <route>` follows `EXPOSES` → `HTTP_CALLS` / `ASYNC_CALLS` → `CALLS`. `connection <microservice>` = inbound/outbound cross-service seams (its positional is a literal service name, not a query). Per-command edge mappings and the rest of the flag surface live in each command's `--help`.
|
|
102
|
+
|
|
103
|
+
**Node id prefixes (from prior results):** `sym:` (Symbol), `route:`/`r:` (Route), `client:`/`c:` (Client), `producer:`/`p:` (Producer). **Symbol FQN:** `<package>.<Type>[.<NestedType>]#<methodName>(<SimpleType1>,…)` — generics erased, no spaces after commas, no-arg `()`, constructor `#<init>(...)`.
|
|
104
|
+
|
|
105
|
+
**Ontology.** Role / symbol-kind / framework / capability values are enumerated in `--help`; client/producer kinds and source layers validate at runtime and surface the accepted set on a typo.
|
|
@@ -30,6 +30,7 @@ from pathlib import Path
|
|
|
30
30
|
|
|
31
31
|
from java_codebase_rag._fdlimit import raise_fd_limit
|
|
32
32
|
from java_codebase_rag._stdio import force_utf8_stdio
|
|
33
|
+
from java_codebase_rag._version import version_string
|
|
33
34
|
|
|
34
35
|
__all__ = ["build_parser", "main", "_console_script_main"]
|
|
35
36
|
|
|
@@ -302,6 +303,44 @@ def _preparse_render_flags(raw: list[str]) -> tuple[str | None, str | None, list
|
|
|
302
303
|
return None, None, list(raw)
|
|
303
304
|
|
|
304
305
|
|
|
306
|
+
# Closed enum taxonomies for the --role / --exclude-role / --java-kind /
|
|
307
|
+
# --framework / --capability filters. Sourced from the canonical literals
|
|
308
|
+
# (mcp_v2.Role, mcp_v2.DeclarationSymbolKind, mcp_v2.Framework) and
|
|
309
|
+
# java_ontology.VALID_CAPABILITIES, and cross-checked by test_jrag_enum_choices.
|
|
310
|
+
# Hardcoded here (not imported) so `jrag --help` stays fast — build_parser
|
|
311
|
+
# imports no backend modules, and importing mcp_v2 costs ~0.7s.
|
|
312
|
+
_ROLE_CHOICES = (
|
|
313
|
+
"CONTROLLER", "SERVICE", "REPOSITORY", "COMPONENT", "CONFIG",
|
|
314
|
+
"ENTITY", "CLIENT", "MAPPER", "DTO", "OTHER",
|
|
315
|
+
)
|
|
316
|
+
_JAVA_KIND_CHOICES = (
|
|
317
|
+
"class", "interface", "enum", "record", "annotation", "method", "constructor",
|
|
318
|
+
)
|
|
319
|
+
_FRAMEWORK_CHOICES = (
|
|
320
|
+
"spring_mvc", "webflux", "kafka", "rabbitmq", "jms", "stream", "feign",
|
|
321
|
+
)
|
|
322
|
+
_CAPABILITY_CHOICES = (
|
|
323
|
+
"MESSAGE_LISTENER", "MESSAGE_PRODUCER", "HTTP_CLIENT",
|
|
324
|
+
"SCHEDULED_TASK", "EXCEPTION_HANDLER",
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _upper_snake(value: str) -> str:
|
|
329
|
+
"""Normalize a role/capability value to its stored UPPER_SNAKE form so
|
|
330
|
+
argparse ``choices=`` accepts flexible casing (``controller`` /
|
|
331
|
+
``scheduled-task`` -> ``CONTROLLER`` / ``SCHEDULED_TASK``). Mirrors the
|
|
332
|
+
role/capability branch of jrag_envelope.normalize_enum."""
|
|
333
|
+
return value.strip().upper().replace("-", "_").replace(" ", "_")
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def _lower_snake(value: str) -> str:
|
|
337
|
+
"""Normalize a java-kind/framework value to its stored lowercase form so
|
|
338
|
+
argparse ``choices=`` accepts flexible casing (``Spring-MVC`` ->
|
|
339
|
+
``spring_mvc``). Mirrors the framework/java_kind branch of
|
|
340
|
+
jrag_envelope.normalize_enum."""
|
|
341
|
+
return value.strip().lower().replace("-", "_").replace(" ", "_")
|
|
342
|
+
|
|
343
|
+
|
|
305
344
|
def build_parser() -> argparse.ArgumentParser:
|
|
306
345
|
"""Argparse builder. Imports no backend modules.
|
|
307
346
|
|
|
@@ -334,11 +373,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
334
373
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
335
374
|
exit_on_error=False,
|
|
336
375
|
)
|
|
376
|
+
parser.add_argument(
|
|
377
|
+
"--version",
|
|
378
|
+
action="version",
|
|
379
|
+
version=version_string(parser.prog),
|
|
380
|
+
)
|
|
337
381
|
subparsers = parser.add_subparsers(dest="command", parser_class=_EnvelopeArgumentParser)
|
|
338
382
|
|
|
339
383
|
# Common flags applied per command via parents=[_common_parser()]. NOT
|
|
340
|
-
# global so commands can override defaults (e.g.
|
|
341
|
-
#
|
|
384
|
+
# global so commands can override defaults (e.g. inspect/orientation
|
|
385
|
+
# default --detail to full). The helper builds a FRESH parser each call so every subparser
|
|
342
386
|
# owns its own --detail Action object — argparse `parents` shares Action
|
|
343
387
|
# objects by reference, and `set_defaults(detail=...)` mutates the shared
|
|
344
388
|
# action's default (CPython walks `self._actions`), so a single shared
|
|
@@ -360,7 +404,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
360
404
|
),
|
|
361
405
|
)
|
|
362
406
|
common.add_argument(
|
|
363
|
-
"--limit", type=int, default=20, help="Cap on results (default 20
|
|
407
|
+
"--limit", type=int, default=20, help="Cap on results (default 20)."
|
|
364
408
|
)
|
|
365
409
|
common.add_argument(
|
|
366
410
|
"--index-dir",
|
|
@@ -455,12 +499,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
455
499
|
default=None,
|
|
456
500
|
help="Node kind (omit for auto-inference from domain flags).",
|
|
457
501
|
)
|
|
458
|
-
find.add_argument("--role", type=
|
|
459
|
-
find.add_argument("--exclude-role", type=
|
|
460
|
-
find.add_argument("--java-kind", type=
|
|
502
|
+
find.add_argument("--role", type=_upper_snake, choices=_ROLE_CHOICES, default=None, help="Filter by role.")
|
|
503
|
+
find.add_argument("--exclude-role", type=_upper_snake, choices=_ROLE_CHOICES, default=None, help="Exclude by role.")
|
|
504
|
+
find.add_argument("--java-kind", type=_lower_snake, choices=_JAVA_KIND_CHOICES, default=None, help="Filter by Java symbol kind.")
|
|
461
505
|
find.add_argument("--annotation", type=str, default=None, help="Filter by annotation.")
|
|
462
|
-
find.add_argument("--capability", type=
|
|
463
|
-
find.add_argument("--framework", type=
|
|
506
|
+
find.add_argument("--capability", type=_upper_snake, choices=_CAPABILITY_CHOICES, default=None, help="Filter by capability.")
|
|
507
|
+
find.add_argument("--framework", type=_lower_snake, choices=_FRAMEWORK_CHOICES, default=None, help="Filter by framework.")
|
|
464
508
|
find.add_argument("--source-layer", type=str, default=None, help="Filter by source layer.")
|
|
465
509
|
find.add_argument("--fqn-contains", type=str, default=None, help="Filter by FQN substring.")
|
|
466
510
|
find.add_argument("--http-method", type=str, default=None, help="Filter by HTTP method (route).")
|
|
@@ -496,8 +540,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
496
540
|
default=None,
|
|
497
541
|
help="Hint for resolve (omitted for broad search).",
|
|
498
542
|
)
|
|
499
|
-
inspect.add_argument("--java-kind", type=
|
|
500
|
-
inspect.add_argument("--role", type=
|
|
543
|
+
inspect.add_argument("--java-kind", type=_lower_snake, choices=_JAVA_KIND_CHOICES, default=None, help="Post-filter by Java symbol kind.")
|
|
544
|
+
inspect.add_argument("--role", type=_upper_snake, choices=_ROLE_CHOICES, default=None, help="Post-filter by role.")
|
|
501
545
|
inspect.add_argument("--fqn-contains", type=str, default=None, help="Post-filter by FQN substring.")
|
|
502
546
|
inspect.set_defaults(handler=_cmd_inspect, detail="full")
|
|
503
547
|
|
|
@@ -512,7 +556,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
512
556
|
"kafka topics live under `topics`."
|
|
513
557
|
),
|
|
514
558
|
)
|
|
515
|
-
http_routes.add_argument("--framework", type=
|
|
559
|
+
http_routes.add_argument("--framework", type=_lower_snake, choices=_FRAMEWORK_CHOICES, default=None, help="Filter by framework.")
|
|
516
560
|
http_routes.add_argument("--path-contains", type=str, default=None, help="Filter by path substring.")
|
|
517
561
|
http_routes.add_argument("--method", type=str, default=None, help="Filter by HTTP method.")
|
|
518
562
|
http_routes.set_defaults(handler=_cmd_routes, detail="full", auto_scope=True)
|
|
@@ -611,8 +655,8 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
611
655
|
default=None,
|
|
612
656
|
help="Hint for resolve (omit for broad search).",
|
|
613
657
|
)
|
|
614
|
-
resolve_parent.add_argument("--java-kind", type=
|
|
615
|
-
resolve_parent.add_argument("--role", type=
|
|
658
|
+
resolve_parent.add_argument("--java-kind", type=_lower_snake, choices=_JAVA_KIND_CHOICES, default=None, help="Post-filter by Java symbol kind.")
|
|
659
|
+
resolve_parent.add_argument("--role", type=_upper_snake, choices=_ROLE_CHOICES, default=None, help="Post-filter by role.")
|
|
616
660
|
resolve_parent.add_argument("--fqn-contains", type=str, default=None, help="Post-filter by FQN substring.")
|
|
617
661
|
|
|
618
662
|
callers = subparsers.add_parser(
|
|
@@ -694,7 +738,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
694
738
|
),
|
|
695
739
|
)
|
|
696
740
|
implementations.add_argument("query", help="Interface FQN or name.")
|
|
697
|
-
implementations.add_argument("--capability", type=
|
|
741
|
+
implementations.add_argument("--capability", type=_upper_snake, choices=_CAPABILITY_CHOICES, default=None, help="Filter implementors by capability.")
|
|
698
742
|
implementations.set_defaults(handler=_cmd_implementations, auto_scope=True)
|
|
699
743
|
|
|
700
744
|
subclasses = subparsers.add_parser(
|
|
@@ -777,16 +821,21 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
777
821
|
decompose.add_argument("--depth", type=int, default=2, help="Neighbour hop count per stage (clamped 1..3, default 2).")
|
|
778
822
|
decompose.add_argument(
|
|
779
823
|
"--follow-calls",
|
|
780
|
-
action=
|
|
824
|
+
action=argparse.BooleanOptionalAction,
|
|
825
|
+
default=True,
|
|
781
826
|
dest="follow_calls",
|
|
782
|
-
help=
|
|
827
|
+
help=(
|
|
828
|
+
"Top up each stage with DECLARES+CALLS type-to-type hops when the "
|
|
829
|
+
"structural INJECTS/EXTENDS/IMPLEMENTS pass under-fills it (default: "
|
|
830
|
+
"on). --no-follow-calls restricts the waterfall to structural edges."
|
|
831
|
+
),
|
|
783
832
|
)
|
|
784
833
|
decompose.add_argument(
|
|
785
|
-
"--
|
|
834
|
+
"--per-stage-limit",
|
|
786
835
|
type=int,
|
|
787
836
|
default=20,
|
|
788
|
-
dest="
|
|
789
|
-
help="Cap on symbols per stage (stage_limit, default 20).",
|
|
837
|
+
dest="per_stage_limit",
|
|
838
|
+
help="Cap on symbols per stage (stage_limit, default 20). Not a stage-count knob.",
|
|
790
839
|
)
|
|
791
840
|
decompose.add_argument(
|
|
792
841
|
"--min-confidence",
|
|
@@ -1094,12 +1143,12 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1094
1143
|
),
|
|
1095
1144
|
)
|
|
1096
1145
|
# NodeFilter flags (same set as `find` filter mode, minus the query-only ones).
|
|
1097
|
-
search.add_argument("--role", type=
|
|
1098
|
-
search.add_argument("--exclude-role", type=
|
|
1099
|
-
search.add_argument("--java-kind", type=
|
|
1146
|
+
search.add_argument("--role", type=_upper_snake, choices=_ROLE_CHOICES, default=None, help="Filter by role.")
|
|
1147
|
+
search.add_argument("--exclude-role", type=_upper_snake, choices=_ROLE_CHOICES, default=None, dest="exclude_role", help="Exclude by role.")
|
|
1148
|
+
search.add_argument("--java-kind", type=_lower_snake, choices=_JAVA_KIND_CHOICES, default=None, dest="java_kind", help="Filter by Java symbol kind.")
|
|
1100
1149
|
search.add_argument("--annotation", type=str, default=None, help="Filter by annotation.")
|
|
1101
|
-
search.add_argument("--capability", type=
|
|
1102
|
-
search.add_argument("--framework", type=
|
|
1150
|
+
search.add_argument("--capability", type=_upper_snake, choices=_CAPABILITY_CHOICES, default=None, help="Filter by capability.")
|
|
1151
|
+
search.add_argument("--framework", type=_lower_snake, choices=_FRAMEWORK_CHOICES, default=None, help="Filter by framework.")
|
|
1103
1152
|
search.add_argument("--fqn-contains", type=str, default=None, dest="fqn_contains", help="Filter by FQN substring.")
|
|
1104
1153
|
search.add_argument(
|
|
1105
1154
|
"--offset",
|
|
@@ -2404,6 +2453,44 @@ def _cmd_callers(args: argparse.Namespace) -> int:
|
|
|
2404
2453
|
edges.append(
|
|
2405
2454
|
{"other_id": ce.src.id, "edge_type": "CALLS", "confidence": ce.confidence}
|
|
2406
2455
|
)
|
|
2456
|
+
# Entry-point awareness. A controller / messaging-listener type is invoked
|
|
2457
|
+
# via the routes its methods EXPOSE (Controller -[:DECLARES]-> method
|
|
2458
|
+
# -[:EXPOSES]-> Route), NOT via in-repo CALLS edges — so find_callers is
|
|
2459
|
+
# typically empty for HTTP handlers. Without this fold, `callers
|
|
2460
|
+
# <Controller>` returns a bug-looking empty list when the controller is the
|
|
2461
|
+
# very thing the agent is investigating. The routes ARE its inbound callers,
|
|
2462
|
+
# so surface them as additional EXPOSES rows alongside any CALLS-in edges.
|
|
2463
|
+
# Gated on having DECLARES.EXPOSES out-edges (covers any entry-point holder,
|
|
2464
|
+
# not just role=CONTROLLER). Routes are additive and usually few, so they do
|
|
2465
|
+
# not count against the CALLS --limit (cf. the callees client/producer path,
|
|
2466
|
+
# which likewise emits its own targets without sharing the CALLS budget).
|
|
2467
|
+
expose_rows = graph._rows( # noqa: SLF001 - one-shot aggregation, cf. _cmd_callees client path
|
|
2468
|
+
"MATCH (t:Symbol {id: $tid})-[:DECLARES]->(m:Symbol)-[e:EXPOSES]->(r:Route) "
|
|
2469
|
+
"RETURN r.id AS rid, r.method AS rmethod, r.path AS rpath, "
|
|
2470
|
+
"r.path_template AS rpt, r.microservice AS rms, "
|
|
2471
|
+
"m.fqn AS via_fqn, e.confidence AS conf",
|
|
2472
|
+
{"tid": root_id},
|
|
2473
|
+
)
|
|
2474
|
+
for row in expose_rows:
|
|
2475
|
+
rid = str(row.get("rid") or "")
|
|
2476
|
+
if not rid or rid in nodes:
|
|
2477
|
+
continue
|
|
2478
|
+
rmethod = str(row.get("rmethod") or "")
|
|
2479
|
+
rpath = str(row.get("rpt") or row.get("rpath") or "")
|
|
2480
|
+
nodes[rid] = {
|
|
2481
|
+
"id": rid,
|
|
2482
|
+
"kind": "route",
|
|
2483
|
+
"fqn": f"{rmethod} {rpath}".strip(),
|
|
2484
|
+
"method": rmethod,
|
|
2485
|
+
"path": rpath,
|
|
2486
|
+
"microservice": str(row.get("rms") or ""),
|
|
2487
|
+
}
|
|
2488
|
+
edge_row: dict = {"other_id": rid, "edge_type": "EXPOSES"}
|
|
2489
|
+
via_fqn = str(row.get("via_fqn") or "")
|
|
2490
|
+
if via_fqn:
|
|
2491
|
+
# Declaring method that exposes the route; rendered at --detail full.
|
|
2492
|
+
edge_row["from_fqn"] = via_fqn
|
|
2493
|
+
edges.append(edge_row)
|
|
2407
2494
|
nodes[root_id] = root_dict
|
|
2408
2495
|
return _emit_traversal(
|
|
2409
2496
|
args, root_id=root_id, nodes=nodes, edges=edges,
|
|
@@ -2956,8 +3043,8 @@ def _cmd_decompose(args: argparse.Namespace) -> int:
|
|
|
2956
3043
|
stages = graph.trace_flow(
|
|
2957
3044
|
seed_fqns=[seed_fqn],
|
|
2958
3045
|
depth=depth,
|
|
2959
|
-
follow_calls=getattr(args, "follow_calls",
|
|
2960
|
-
stage_limit=getattr(args, "
|
|
3046
|
+
follow_calls=getattr(args, "follow_calls", True),
|
|
3047
|
+
stage_limit=getattr(args, "per_stage_limit", 20),
|
|
2961
3048
|
min_call_confidence=getattr(args, "min_confidence", 0.0),
|
|
2962
3049
|
exclude_external=not getattr(args, "include_external", False),
|
|
2963
3050
|
microservice=args.service,
|
|
@@ -2983,12 +3070,12 @@ def _cmd_decompose(args: argparse.Namespace) -> int:
|
|
|
2983
3070
|
edge_row["from_fqn"] = via.from_fqn
|
|
2984
3071
|
edges.append(edge_row)
|
|
2985
3072
|
# --limit is inherited from common but does not cap decompose (trace_flow
|
|
2986
|
-
# is stage-limited via --
|
|
3073
|
+
# is stage-limited via --per-stage-limit, not a total edge count). Warn when the
|
|
2987
3074
|
# user explicitly set --limit away from the default so they get a signal
|
|
2988
3075
|
# rather than a silent multi-stage dump (Fix 4).
|
|
2989
3076
|
if args.limit is not None and args.limit != 20:
|
|
2990
3077
|
warnings.append(
|
|
2991
|
-
"--limit does not apply to decompose; use --
|
|
3078
|
+
"--limit does not apply to decompose; use --per-stage-limit to cap per-stage breadth"
|
|
2992
3079
|
)
|
|
2993
3080
|
return _emit_traversal(
|
|
2994
3081
|
args, root_id=root_id, nodes=nodes, edges=edges,
|
|
@@ -472,11 +472,19 @@ def _render_traversal(envelope: Envelope, *, noun: str, detail: str = "normal")
|
|
|
472
472
|
by_stage[s].append(e)
|
|
473
473
|
for s in stage_order:
|
|
474
474
|
stage_edges = by_stage[s]
|
|
475
|
-
|
|
475
|
+
# Preserve first-seen order so a mixed stage reads naturally
|
|
476
|
+
# (e.g. `stage 1 (service, component):`) instead of dropping the
|
|
477
|
+
# role label entirely — the role allow-list is the whole point of a
|
|
478
|
+
# role-waterfall, so hiding it on the busiest stages is a loss.
|
|
479
|
+
seen: list[str] = []
|
|
480
|
+
for e in stage_edges:
|
|
481
|
+
r = str(e.get("role") or "").strip().lower()
|
|
482
|
+
if r and r not in seen:
|
|
483
|
+
seen.append(r)
|
|
476
484
|
if s == 0:
|
|
477
485
|
header = "stage 0 (seed):"
|
|
478
|
-
elif
|
|
479
|
-
header = f"stage {s} ({
|
|
486
|
+
elif seen:
|
|
487
|
+
header = f"stage {s} ({', '.join(seen)}):"
|
|
480
488
|
else:
|
|
481
489
|
header = f"stage {s}:"
|
|
482
490
|
lines.append(header)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: java-codebase-rag
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.4
|
|
4
4
|
Summary: MCP server for semantic + structural search over Java codebases
|
|
5
5
|
Author: HumanBean17
|
|
6
6
|
License-Expression: MIT
|
|
@@ -168,6 +168,7 @@ jrag entities # JPA entities
|
|
|
168
168
|
|
|
169
169
|
# Traversals (all resolve-first)
|
|
170
170
|
jrag callers ChatService#assign(Request) # who calls me?
|
|
171
|
+
jrag callers ChatIngressController # controller: also lists its EXPOSES routes
|
|
171
172
|
jrag callees ChatService#assign(Request) # what do I call?
|
|
172
173
|
jrag hierarchy AbstractBase # type tree (parents + children)
|
|
173
174
|
jrag implementations PaymentProcessor # classes implementing an interface
|
|
@@ -22,6 +22,7 @@ server.py
|
|
|
22
22
|
java_codebase_rag/__init__.py
|
|
23
23
|
java_codebase_rag/_fdlimit.py
|
|
24
24
|
java_codebase_rag/_stdio.py
|
|
25
|
+
java_codebase_rag/_version.py
|
|
25
26
|
java_codebase_rag/cli.py
|
|
26
27
|
java_codebase_rag/cli_format.py
|
|
27
28
|
java_codebase_rag/cli_progress.py
|
|
@@ -79,6 +80,7 @@ tests/test_installer_integration.py
|
|
|
79
80
|
tests/test_installer_surface.py
|
|
80
81
|
tests/test_java_codebase_rag_cli.py
|
|
81
82
|
tests/test_jrag_auto_scope.py
|
|
83
|
+
tests/test_jrag_enum_choices.py
|
|
82
84
|
tests/test_jrag_envelope.py
|
|
83
85
|
tests/test_jrag_listing.py
|
|
84
86
|
tests/test_jrag_locate.py
|
|
@@ -111,4 +113,5 @@ tests/test_schema_consistency.py
|
|
|
111
113
|
tests/test_search_lancedb.py
|
|
112
114
|
tests/test_search_lancedb_capability.py
|
|
113
115
|
tests/test_string_value_atoms.py
|
|
114
|
-
tests/test_vectors_progress.py
|
|
116
|
+
tests/test_vectors_progress.py
|
|
117
|
+
tests/test_version_flag.py
|