java-codebase-rag 0.11.2__py3-none-any.whl → 0.12.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.
- java_codebase_rag/_deprecation.py +103 -0
- java_codebase_rag/_version.py +2 -2
- java_codebase_rag/ast/ast_java.py +22 -0
- java_codebase_rag/ast/ast_kotlin.py +1794 -0
- java_codebase_rag/ast/chunk_heuristics.py +26 -5
- java_codebase_rag/ast/language.py +117 -0
- java_codebase_rag/cli.py +17 -17
- java_codebase_rag/cli_dispatch.py +251 -0
- java_codebase_rag/config.py +8 -8
- java_codebase_rag/eval/runner.py +3 -3
- java_codebase_rag/graph/build_ast_graph.py +130 -8
- java_codebase_rag/graph/graph_enrich.py +8 -5
- java_codebase_rag/graph/ladybug_queries.py +1 -1
- java_codebase_rag/graph/path_filtering.py +39 -7
- java_codebase_rag/index/java_index_flow_lancedb.py +160 -15
- java_codebase_rag/install_data/agents/explorer-rag-cli.md +6 -4
- java_codebase_rag/install_data/agents/explorer-rag-enhanced.md +4 -4
- java_codebase_rag/install_data/skills/explore-codebase/SKILL.md +4 -4
- java_codebase_rag/install_data/skills/explore-codebase-cli/SKILL.md +5 -5
- java_codebase_rag/installer.py +15 -15
- java_codebase_rag/jrag.py +25 -11
- java_codebase_rag/lance_optimize.py +7 -7
- java_codebase_rag/mcp/mcp_v2.py +2 -2
- java_codebase_rag/mcp/server.py +6 -4
- java_codebase_rag/pipeline.py +4 -4
- java_codebase_rag/progress.py +1 -1
- java_codebase_rag/search/search_lexical.py +1 -1
- java_codebase_rag/search/search_scoring.py +19 -5
- java_codebase_rag/watch/lock.py +1 -1
- java_codebase_rag/watch/watcher.py +45 -21
- {java_codebase_rag-0.11.2.dist-info → java_codebase_rag-0.12.0.dist-info}/METADATA +31 -22
- {java_codebase_rag-0.11.2.dist-info → java_codebase_rag-0.12.0.dist-info}/RECORD +36 -32
- java_codebase_rag-0.12.0.dist-info/entry_points.txt +5 -0
- java_codebase_rag-0.11.2.dist-info/entry_points.txt +0 -4
- {java_codebase_rag-0.11.2.dist-info → java_codebase_rag-0.12.0.dist-info}/WHEEL +0 -0
- {java_codebase_rag-0.11.2.dist-info → java_codebase_rag-0.12.0.dist-info}/licenses/LICENSE +0 -0
- {java_codebase_rag-0.11.2.dist-info → java_codebase_rag-0.12.0.dist-info}/top_level.txt +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
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)."
|
|
3
|
+
description: "MUST BE USED PROACTIVELY. Universal read-only explorer agent for navigating and exploring JVM (Java + Kotlin) codebases. Combines graph navigation via the `jrag` CLI (call chains, routes, service boundaries, clients, producers, impact, FQN resolution) with `jrag search` (locate code/config by meaning, keywords, or natural language) and 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
4
|
---
|
|
5
5
|
|
|
6
|
-
You are a universal codebase explorer — a read-only search and navigation specialist
|
|
6
|
+
You are a universal codebase explorer — a read-only search and navigation specialist. Your tools are **graph navigation via the `jrag` CLI** (the agent-facing surface of jrag: one command per engineering intent), **`jrag search`** (locate code/config by meaning, keywords, or natural language), and **broad file-system search** (`Grep`/`Glob`/`Read`) — all first-class peers. Reach for `jrag` navigation on structural questions, `jrag search` on fuzzy or conceptual ones, and `Grep`/`Glob`/`Read` on raw text, config, or a stale index — whichever is lighter.
|
|
7
7
|
|
|
8
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
9
|
|
|
@@ -18,7 +18,7 @@ You drive **`jrag` shell commands**, not the MCP tools (`search`/`find`/`describ
|
|
|
18
18
|
|
|
19
19
|
## Tool Inventory
|
|
20
20
|
|
|
21
|
-
-
|
|
21
|
+
- **`jrag` CLI — navigate & search:** one command per intent — graph navigation (`callers`, `callees`, `hierarchy`, `implementations`, `dependents`, `impact`, `flow`, `http-routes`, `http-clients`, `producers`, `topics`, `overview`), `search` (locate code or config by meaning, keywords, or natural language), and `find`/`inspect` (resolve identifiers; list nodes by role/kind). Whole-codebase structural queries and fuzzy discovery alike. Pass it names; it resolves internally (no raw IDs). Requires an index (see **jrag surface**).
|
|
22
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
23
|
- **Other:** `Bash` (read-only: `git log`, `git blame`, `ls`, `find`), `WebSearch`, `WebFetch`.
|
|
24
24
|
|
|
@@ -56,6 +56,8 @@ You drive **`jrag` shell commands**, not the MCP tools (`search`/`find`/`describ
|
|
|
56
56
|
|
|
57
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
58
|
|
|
59
|
+
**Rules of thumb:** structure beats search for exact questions (`jrag find`/`inspect` + traversal); search beats structure for fuzzy discovery (`jrag search`); raw text / config / history beats both (`Grep`/`Glob`/`Bash`); file-system beats a stale index.
|
|
60
|
+
|
|
59
61
|
---
|
|
60
62
|
|
|
61
63
|
## Workflow Patterns
|
|
@@ -72,7 +74,7 @@ You drive **`jrag` shell commands**, not the MCP tools (`search`/`find`/`describ
|
|
|
72
74
|
|
|
73
75
|
| Symptom | Fix |
|
|
74
76
|
| ------- | --- |
|
|
75
|
-
| `jrag status` exits 2 | Run `
|
|
77
|
+
| `jrag status` exits 2 | Run `jrag init --source-root <root>`; retry |
|
|
76
78
|
| `status: not_found` | `jrag search "<query>"`; or `find --fqn-contains`; fallback `Grep` |
|
|
77
79
|
| `many` candidates | Add `--kind`/`--role`/`--fqn-contains`/`--service`; re-run |
|
|
78
80
|
| `find` too broad | Add `--service`, `--fqn-contains`, `--path-contains`, `--topic-contains` |
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: explorer-rag-enhanced
|
|
3
|
-
description: "MUST BE USED PROACTIVELY. Universal read-only explorer agent. Combines
|
|
3
|
+
description: "MUST BE USED PROACTIVELY. Universal read-only explorer agent. Combines jrag graph navigation (call chains, service boundaries, routes, impact analysis, 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' questions. Read-only — never edits files."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
You are a universal codebase explorer — a read-only search and navigation specialist that combines **graph-based structural analysis** (
|
|
6
|
+
You are a universal codebase explorer — a read-only search and navigation specialist that combines **graph-based structural analysis** (jrag MCP) with **broad file-system search** (grep, glob, file reading).
|
|
7
7
|
|
|
8
8
|
## Core Principles
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ You are a universal codebase explorer — a read-only search and navigation spec
|
|
|
14
14
|
|
|
15
15
|
## Tool Inventory
|
|
16
16
|
|
|
17
|
-
- **Graph (
|
|
17
|
+
- **Graph (jrag MCP):** `search`, `find`, `describe`, `neighbors`, `resolve`. Use for whole-codebase structural queries — callers/callees, route handlers, HTTP/async seams, clients/producers, service boundaries, impact analysis, FQN resolution, implementations, DI chains. Node kinds: `Symbol` (types/methods), `Route` (HTTP/messaging entry points), `Client` (outbound HTTP), `Producer` (outbound async). Indexed content: Java + SQL + YAML (`table`: `java`, `sql`, `yaml`, `all`). **Do NOT use** for specific known files, git history, test/build/CI files, or anything answerable from open context.
|
|
18
18
|
- **File-system:** `Grep` (contents), `Glob` (name/path patterns), `Read` (files — `offset`/`limit` for large; excerpts over dumps). Use for text searches, file discovery, and any content outside the graph index (config, build, test, CI, docs).
|
|
19
19
|
- **Other:** `Bash` (read-only: `git log`, `git blame`, `ls`, `find`), `WebSearch`, `WebFetch`.
|
|
20
20
|
|
|
@@ -45,7 +45,7 @@ You are a universal codebase explorer — a read-only search and navigation spec
|
|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
48
|
-
## Graph Navigation Reference (
|
|
48
|
+
## Graph Navigation Reference (jrag MCP)
|
|
49
49
|
|
|
50
50
|
### Forced reasoning preamble (every MCP call)
|
|
51
51
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: explore-codebase
|
|
3
|
-
description: "MUST BE USED PROACTIVELY. Universal read-only codebase exploration. Combines
|
|
3
|
+
description: "MUST BE USED PROACTIVELY. Universal read-only codebase exploration. Combines jrag graph navigation (call chains, routes, service boundaries, impact analysis, FQN resolution) with broad file-system search (grep, glob, file reading). Use for any exploration: 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
4
|
---
|
|
5
5
|
|
|
6
6
|
# /explore-codebase — Universal codebase exploration
|
|
7
7
|
|
|
8
|
-
Read-only exploration combining **
|
|
8
|
+
Read-only exploration combining **jrag graph navigation** with **broad file-system search**.
|
|
9
9
|
|
|
10
10
|
Use any time you must search, locate, navigate, or explore. **Do NOT use when** the answer is already in context or for a single known file — read it directly.
|
|
11
11
|
|
|
@@ -17,7 +17,7 @@ Use any time you must search, locate, navigate, or explore. **Do NOT use when**
|
|
|
17
17
|
|
|
18
18
|
## Tool Inventory
|
|
19
19
|
|
|
20
|
-
- **Graph (
|
|
20
|
+
- **Graph (jrag MCP):** `search`, `find`, `describe`, `neighbors`, `resolve`. Node kinds: `Symbol` (types/methods), `Route` (HTTP/messaging entry points), `Client` (outbound HTTP), `Producer` (outbound async). Indexed content: Java + SQL + YAML (`table`: `java`, `sql`, `yaml`, `all`).
|
|
21
21
|
- **File-system:** `Grep` (content/regex), `Glob` (name/path patterns), `Read` (`offset`/`limit` for large files).
|
|
22
22
|
- **Other:** `Bash` (read-only: `git log`, `git blame`, `ls`, `find`), `WebSearch`/`WebFetch`.
|
|
23
23
|
|
|
@@ -50,7 +50,7 @@ Use any time you must search, locate, navigate, or explore. **Do NOT use when**
|
|
|
50
50
|
|
|
51
51
|
---
|
|
52
52
|
|
|
53
|
-
## Graph Navigation Reference (
|
|
53
|
+
## Graph Navigation Reference (jrag MCP)
|
|
54
54
|
|
|
55
55
|
**Ontology: 17.** If results look structurally wrong or empty across tools, the index may be missing/stale — ask the operator to rebuild. Responses may carry `hints_structured` (suggested next calls) and `advisories` — advisory only; ignore when `success` is false.
|
|
56
56
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
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."
|
|
3
|
+
description: "MUST BE USED PROACTIVELY. Universal JVM (Java + Kotlin) codebase exploration (CLI surface): graph navigation (`jrag` callers/callees/routes/impact/flow/…) plus `jrag search` (locate code/config by meaning or keywords) and file-system search. 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
4
|
---
|
|
5
5
|
|
|
6
6
|
## Core Principles
|
|
@@ -11,7 +11,7 @@ description: "MUST BE USED PROACTIVELY. Universal codebase exploration (CLI surf
|
|
|
11
11
|
|
|
12
12
|
## Tool Inventory
|
|
13
13
|
|
|
14
|
-
-
|
|
14
|
+
- **`jrag` CLI — navigate & search:** one command per intent — graph navigation (`callers`, `callees`, `hierarchy`, `implementations`, `dependents`, `impact`, `flow`, `http-routes`, `http-clients`, `producers`, `topics`, `overview`), `search` (locate code or config by meaning, keywords, or natural language), and `find`/`inspect` (resolve identifiers; list nodes by role/kind). 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) and fuzzy discovery alike. 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
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
16
|
- **Other:** `Bash` (read-only: `git log`, `git blame`, `ls`, `find`), `WebSearch`/`WebFetch`.
|
|
17
17
|
|
|
@@ -51,7 +51,7 @@ description: "MUST BE USED PROACTIVELY. Universal codebase exploration (CLI surf
|
|
|
51
51
|
|
|
52
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
53
|
|
|
54
|
-
**Rules of thumb:** structure beats
|
|
54
|
+
**Rules of thumb:** structure beats search for exact questions (`jrag find`/`inspect` + traversal); search beats structure for fuzzy discovery (`jrag search`); raw text / config / history beats both (`Grep`/`Glob`/`Bash`); file-system beats a stale index.
|
|
55
55
|
|
|
56
56
|
---
|
|
57
57
|
|
|
@@ -70,13 +70,13 @@ description: "MUST BE USED PROACTIVELY. Universal codebase exploration (CLI surf
|
|
|
70
70
|
|
|
71
71
|
| Symptom | Fix |
|
|
72
72
|
| ------- | --- |
|
|
73
|
-
| `status: error` "No index at …" | Run `
|
|
73
|
+
| `status: error` "No index at …" | Run `jrag init --source-root <root>`; retry |
|
|
74
74
|
| `status: not_found` | `jrag search "<query>"`; or `find --fqn-contains …`; fallback `Grep` |
|
|
75
75
|
| `many` candidates | Add `--kind`/`--role`/`--fqn-contains`/`--service`; re-run |
|
|
76
76
|
| `find` too broad | Add `--service`, `--fqn-contains`, `--path-contains`, `--topic-contains` |
|
|
77
77
|
| Empty `search` | Try `--table all`; `find --fqn-contains`; `Grep` |
|
|
78
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 (`
|
|
79
|
+
| Empty across commands | Index missing/stale → `Grep`/`Glob`/`Read`; ask operator to rebuild (`jrag reprocess`) |
|
|
80
80
|
| CLI vs file disagree | **Trust the file**; report stale index |
|
|
81
81
|
| `--offset` rejected | Only `find`/`search` accept it; others narrow via filters |
|
|
82
82
|
| Wrong node picked | Resolve ambiguous — pass `--kind` |
|
java_codebase_rag/installer.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Interactive installer module for
|
|
1
|
+
"""Interactive installer module for jrag.
|
|
2
2
|
|
|
3
3
|
This module provides the `install` subcommand that walks users through:
|
|
4
4
|
1. Java source detection
|
|
@@ -605,13 +605,13 @@ def resolve_mcp_command(*, non_interactive: bool, surface: Surface = "mcp") -> s
|
|
|
605
605
|
print(f"Error: `{display_name}` not found on PATH.")
|
|
606
606
|
if surface == "mcp":
|
|
607
607
|
print(
|
|
608
|
-
"Ensure `
|
|
608
|
+
"Ensure `jrag` is installed, then re-run with "
|
|
609
609
|
"`--non-interactive --agent <host>`."
|
|
610
610
|
)
|
|
611
611
|
else:
|
|
612
612
|
print(
|
|
613
|
-
"Ensure `
|
|
614
|
-
"
|
|
613
|
+
"Ensure the `jrag` console script is installed, "
|
|
614
|
+
"then re-run with `--non-interactive --agent <host>`."
|
|
615
615
|
)
|
|
616
616
|
raise SystemExit(2)
|
|
617
617
|
|
|
@@ -982,7 +982,7 @@ def update_gitignore(cwd: Path) -> None:
|
|
|
982
982
|
|
|
983
983
|
if not already_present:
|
|
984
984
|
lines.append("")
|
|
985
|
-
lines.append("#
|
|
985
|
+
lines.append("# jrag index directory")
|
|
986
986
|
lines.append(".java-codebase-rag/")
|
|
987
987
|
gitignore_path.write_text("\n".join(lines), encoding="utf-8")
|
|
988
988
|
|
|
@@ -998,7 +998,7 @@ def _index_progress_header(subcommand: str, source_root: Path, index_dir: Path)
|
|
|
998
998
|
|
|
999
999
|
print(
|
|
1000
1000
|
bold(
|
|
1001
|
-
f"
|
|
1001
|
+
f"jrag {subcommand} · source={source_root.resolve()} "
|
|
1002
1002
|
f"· index={index_dir.resolve()}"
|
|
1003
1003
|
),
|
|
1004
1004
|
file=sys.stderr,
|
|
@@ -1013,7 +1013,7 @@ def _index_progress_footer(subcommand: str, started: float, *, ok: bool) -> None
|
|
|
1013
1013
|
elapsed = time.perf_counter() - started
|
|
1014
1014
|
marker = styled_check() if ok else styled_cross()
|
|
1015
1015
|
print(
|
|
1016
|
-
f"{marker} {bold(f'
|
|
1016
|
+
f"{marker} {bold(f'jrag {subcommand} · finished in {elapsed:.2f}s')}",
|
|
1017
1017
|
file=sys.stderr,
|
|
1018
1018
|
flush=True,
|
|
1019
1019
|
)
|
|
@@ -1061,7 +1061,7 @@ def run_init_if_needed(
|
|
|
1061
1061
|
|
|
1062
1062
|
has_existing, _ = index_dir_has_existing_artifacts(index_dir)
|
|
1063
1063
|
if has_existing:
|
|
1064
|
-
print("Index already exists. Run `
|
|
1064
|
+
print("Index already exists. Run `jrag reprocess` to rebuild.")
|
|
1065
1065
|
return None # skipped, not failed
|
|
1066
1066
|
|
|
1067
1067
|
cfg = resolve_operator_config(
|
|
@@ -1109,7 +1109,7 @@ def run_init_if_needed(
|
|
|
1109
1109
|
else:
|
|
1110
1110
|
if vectors_skipped:
|
|
1111
1111
|
print(
|
|
1112
|
-
"
|
|
1112
|
+
"jrag: vectors skipped — vector stack not installed on this "
|
|
1113
1113
|
"platform (graph-only mode). Building graph only; semantic search is unavailable.",
|
|
1114
1114
|
file=sys.stderr,
|
|
1115
1115
|
)
|
|
@@ -1750,7 +1750,7 @@ def run_update(
|
|
|
1750
1750
|
|
|
1751
1751
|
if not configured_hosts:
|
|
1752
1752
|
print("No configured agent hosts found.")
|
|
1753
|
-
print("Run `
|
|
1753
|
+
print("Run `jrag install` first.")
|
|
1754
1754
|
return EXIT_FATAL
|
|
1755
1755
|
|
|
1756
1756
|
print(f"Found {len(configured_hosts)} configured host(s).")
|
|
@@ -1800,7 +1800,7 @@ def run_update(
|
|
|
1800
1800
|
f"'{chosen_surface}' surface."
|
|
1801
1801
|
)
|
|
1802
1802
|
print(
|
|
1803
|
-
"Ensure `
|
|
1803
|
+
"Ensure `jrag` is installed, then re-run `update "
|
|
1804
1804
|
f"--surface {chosen_surface}`."
|
|
1805
1805
|
)
|
|
1806
1806
|
return EXIT_PARTIAL
|
|
@@ -1907,11 +1907,11 @@ def run_update(
|
|
|
1907
1907
|
|
|
1908
1908
|
if not index_exists:
|
|
1909
1909
|
print("\nNo index found.")
|
|
1910
|
-
print("Run `
|
|
1910
|
+
print("Run `jrag install` to create one.")
|
|
1911
1911
|
return EXIT_PARTIAL if has_artifact_failures else EXIT_SUCCESS
|
|
1912
1912
|
|
|
1913
1913
|
# Run increment: LanceDB catch-up + incremental graph rebuild.
|
|
1914
|
-
# Mirrors `
|
|
1914
|
+
# Mirrors `jrag increment` so both index layers stay current.
|
|
1915
1915
|
# The "graph not implemented" warning belongs only on the vectors-only path
|
|
1916
1916
|
# (increment --vectors-only), where the graph step is deliberately skipped.
|
|
1917
1917
|
if not dry_run:
|
|
@@ -1955,7 +1955,7 @@ def run_update(
|
|
|
1955
1955
|
else:
|
|
1956
1956
|
if vectors_skipped:
|
|
1957
1957
|
print(
|
|
1958
|
-
"
|
|
1958
|
+
"jrag: vectors skipped — vector stack not installed on this "
|
|
1959
1959
|
"platform (graph-only mode). Running graph catch-up only.",
|
|
1960
1960
|
file=sys.stderr,
|
|
1961
1961
|
)
|
|
@@ -1977,7 +1977,7 @@ def run_update(
|
|
|
1977
1977
|
# check + the Warning line carrying the graph caveat.
|
|
1978
1978
|
print(
|
|
1979
1979
|
f"\nWarning: incremental graph update failed (exit {g.returncode}). "
|
|
1980
|
-
"Run `
|
|
1980
|
+
"Run `jrag reprocess` for a full rebuild.",
|
|
1981
1981
|
file=sys.stderr,
|
|
1982
1982
|
)
|
|
1983
1983
|
except BaseException:
|
java_codebase_rag/jrag.py
CHANGED
|
@@ -1095,8 +1095,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1095
1095
|
help="List imports declared in a file (tree-sitter parse + resolve_v2).",
|
|
1096
1096
|
parents=[_common_parser()],
|
|
1097
1097
|
description=(
|
|
1098
|
-
"Parse <file> with tree-sitter
|
|
1099
|
-
"
|
|
1098
|
+
"Parse <file> with tree-sitter via the language backend "
|
|
1099
|
+
"(backend_for(...).parse — parse_java for .java, parse_kotlin for "
|
|
1100
|
+
".kt), walk its import nodes, and resolve each imported FQN via resolve_v2 "
|
|
1100
1101
|
"against the graph. Returns one node per import: resolved graph Symbol "
|
|
1101
1102
|
"when resolve_v2 hits, or an unresolved placeholder carrying the raw FQN "
|
|
1102
1103
|
"otherwise. Static and wildcard imports are included (marked in the row)."
|
|
@@ -1355,7 +1356,7 @@ def _load_graph(cfg): # type: ignore[no-untyped-def]
|
|
|
1355
1356
|
"""Load the LadybugGraph with actionable error envelopes.
|
|
1356
1357
|
|
|
1357
1358
|
* missing index -> ``_IndexNotFound`` (caught in ``main`` -> envelope with
|
|
1358
|
-
a ``
|
|
1359
|
+
a ``jrag init --source-root <root>`` remediation).
|
|
1359
1360
|
* ontology-mismatch (``RuntimeError`` from ``LadybugGraph.get``) ->
|
|
1360
1361
|
``_IndexStale`` (caught in ``main`` -> envelope with a rebuild hint).
|
|
1361
1362
|
"""
|
|
@@ -1365,7 +1366,7 @@ def _load_graph(cfg): # type: ignore[no-untyped-def]
|
|
|
1365
1366
|
if not LadybugGraph.exists(ladybug_path):
|
|
1366
1367
|
raise _IndexNotFound(
|
|
1367
1368
|
f"No index at {cfg.ladybug_path}. "
|
|
1368
|
-
"Run:
|
|
1369
|
+
"Run: jrag init --source-root <root>"
|
|
1369
1370
|
)
|
|
1370
1371
|
try:
|
|
1371
1372
|
return LadybugGraph.get(ladybug_path)
|
|
@@ -3604,12 +3605,13 @@ def _cmd_imports(args: argparse.Namespace) -> int:
|
|
|
3604
3605
|
"""imports <file> — tree-sitter parse + resolve_v2 per imported FQN.
|
|
3605
3606
|
|
|
3606
3607
|
Reads <file> from disk (cfg.source_root / <file> for relative paths),
|
|
3607
|
-
parses
|
|
3608
|
+
parses via the language backend (backend_for(...).parse — parse_java for
|
|
3609
|
+
.java, parse_kotlin for .kt), walks explicit_imports (dict: simple_name
|
|
3608
3610
|
-> FQN), then resolves each FQN via resolve_v2 against the graph. Returns
|
|
3609
3611
|
a node per import: resolved graph Symbol when resolve_v2 hits (status=one),
|
|
3610
3612
|
or an unresolved placeholder carrying the raw FQN otherwise.
|
|
3611
3613
|
"""
|
|
3612
|
-
from java_codebase_rag.ast.
|
|
3614
|
+
from java_codebase_rag.ast.language import backend_for
|
|
3613
3615
|
from java_codebase_rag.analysis.resolve_service import resolve_v2
|
|
3614
3616
|
|
|
3615
3617
|
from java_codebase_rag.jrag_envelope import Envelope, next_actions_hook
|
|
@@ -3638,14 +3640,26 @@ def _cmd_imports(args: argparse.Namespace) -> int:
|
|
|
3638
3640
|
print(render(env, fmt=args.format, detail=args.detail))
|
|
3639
3641
|
return 2
|
|
3640
3642
|
|
|
3641
|
-
#
|
|
3642
|
-
#
|
|
3643
|
-
#
|
|
3644
|
-
#
|
|
3643
|
+
# The backend parse (backend_for(...).parse — parse_java / parse_kotlin)
|
|
3644
|
+
# is robust to invalid source (returns an empty JavaFileAst on parse
|
|
3645
|
+
# errors, never raises). It builds imports from the `import_declaration`
|
|
3646
|
+
# tree-sitter nodes (Java path: `_import_declaration_is_static` at
|
|
3647
|
+
# ast_java.py:905 and the scoped_identifier child walk at ast_java.py:2658).
|
|
3645
3648
|
# explicit_imports: dict[str, str] = simple_name -> FQN (non-wildcard,
|
|
3646
3649
|
# non-static); we also surface wildcard/static imports as unresolved rows so
|
|
3647
3650
|
# the agent sees the full import block.
|
|
3648
|
-
|
|
3651
|
+
backend = backend_for(args.file)
|
|
3652
|
+
if backend is None:
|
|
3653
|
+
env = Envelope(
|
|
3654
|
+
status="error",
|
|
3655
|
+
message=(
|
|
3656
|
+
f"no language backend registered for {args.file!r} "
|
|
3657
|
+
f"(suffix {Path(args.file).suffix!r} not in registry)"
|
|
3658
|
+
),
|
|
3659
|
+
)
|
|
3660
|
+
print(render(env, fmt=args.format, detail=args.detail))
|
|
3661
|
+
return 2
|
|
3662
|
+
ast = backend.parse(src, filename=args.file)
|
|
3649
3663
|
nodes: dict[str, dict] = {}
|
|
3650
3664
|
edges: list[dict] = []
|
|
3651
3665
|
warnings: list[str] = []
|
|
@@ -139,7 +139,7 @@ async def optimize_lance_tables(
|
|
|
139
139
|
existing = await _list_table_names(db)
|
|
140
140
|
except Exception as exc:
|
|
141
141
|
print(
|
|
142
|
-
f"
|
|
142
|
+
f"jrag: optimize: failed to list tables in "
|
|
143
143
|
f"{index_dir}: {exc}",
|
|
144
144
|
file=sys.stderr,
|
|
145
145
|
)
|
|
@@ -151,7 +151,7 @@ async def optimize_lance_tables(
|
|
|
151
151
|
results[name] = "skipped"
|
|
152
152
|
if not quiet:
|
|
153
153
|
print(
|
|
154
|
-
f"
|
|
154
|
+
f"jrag: optimize: {name} absent, skipped",
|
|
155
155
|
file=sys.stderr,
|
|
156
156
|
)
|
|
157
157
|
continue
|
|
@@ -161,7 +161,7 @@ async def optimize_lance_tables(
|
|
|
161
161
|
results[name] = f"error: open failed: {exc}"
|
|
162
162
|
failed = True
|
|
163
163
|
print(
|
|
164
|
-
f"
|
|
164
|
+
f"jrag: optimize: {name} open failed: {exc}",
|
|
165
165
|
file=sys.stderr,
|
|
166
166
|
)
|
|
167
167
|
continue
|
|
@@ -205,7 +205,7 @@ async def optimize_lance_tables(
|
|
|
205
205
|
w in low for w in ("exist", "duplicate", "already", "same name")
|
|
206
206
|
) and not quiet:
|
|
207
207
|
print(
|
|
208
|
-
f"
|
|
208
|
+
f"jrag: optimize: {name} id-index skipped: {exc}",
|
|
209
209
|
file=sys.stderr,
|
|
210
210
|
)
|
|
211
211
|
# Best-effort FTS index at index time (PR-SEARCH-3) so hybrid
|
|
@@ -223,19 +223,19 @@ async def optimize_lance_tables(
|
|
|
223
223
|
w in low for w in ("exist", "duplicate", "already", "same name")
|
|
224
224
|
) and not quiet:
|
|
225
225
|
print(
|
|
226
|
-
f"
|
|
226
|
+
f"jrag: optimize: {name} fts skipped: {exc}",
|
|
227
227
|
file=sys.stderr,
|
|
228
228
|
)
|
|
229
229
|
if not quiet:
|
|
230
230
|
print(
|
|
231
|
-
f"
|
|
231
|
+
f"jrag: optimize: {name} ok",
|
|
232
232
|
file=sys.stderr,
|
|
233
233
|
)
|
|
234
234
|
else:
|
|
235
235
|
results[name] = f"error: {last_exc}"
|
|
236
236
|
failed = True
|
|
237
237
|
print(
|
|
238
|
-
f"
|
|
238
|
+
f"jrag: optimize: {name} failed: {last_exc}",
|
|
239
239
|
file=sys.stderr,
|
|
240
240
|
)
|
|
241
241
|
finally:
|
java_codebase_rag/mcp/mcp_v2.py
CHANGED
|
@@ -1265,7 +1265,7 @@ def find_v2(
|
|
|
1265
1265
|
_DESCRIBE_UCS_ID_MESSAGE = (
|
|
1266
1266
|
"UnresolvedCallSite ids (ucs:…) are not describable — use describe(caller_method_id) "
|
|
1267
1267
|
"for record.data.unresolved_call_sites, neighbors(..., include_unresolved=True), "
|
|
1268
|
-
"or
|
|
1268
|
+
"or jrag unresolved-calls list --method-id <caller_id>"
|
|
1269
1269
|
)
|
|
1270
1270
|
|
|
1271
1271
|
|
|
@@ -1363,7 +1363,7 @@ def describe_v2(
|
|
|
1363
1363
|
if total > len(inline):
|
|
1364
1364
|
data["unresolved_call_sites_footer"] = (
|
|
1365
1365
|
f"{total} unresolved call sites — see "
|
|
1366
|
-
f"
|
|
1366
|
+
f"jrag unresolved-calls list --method-id {node_id} for the full list"
|
|
1367
1367
|
)
|
|
1368
1368
|
record = NodeRecord(id=ref.id, kind=kind, fqn=ref.fqn, data=data, edge_summary=edge_summary)
|
|
1369
1369
|
raw_struct, raw_advisories = _hints_or_skip("describe", {"success": True, "record": record.model_dump()})
|
java_codebase_rag/mcp/server.py
CHANGED
|
@@ -9,6 +9,7 @@ import time
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import Literal
|
|
11
11
|
|
|
12
|
+
from java_codebase_rag._deprecation import maybe_warn_legacy_alias
|
|
12
13
|
from java_codebase_rag.mcp import mcp_v2
|
|
13
14
|
from java_codebase_rag.analysis import resolve_service
|
|
14
15
|
from java_codebase_rag.search.index_common import SBERT_MODEL
|
|
@@ -52,7 +53,7 @@ _INSTRUCTIONS = (
|
|
|
52
53
|
"Successful responses from any tool may include `hints_structured` (tool call suggestions with a `reason` field) and `advisories` (pure informational text) when hints are enabled. "
|
|
53
54
|
"Edge labels: EXTENDS, IMPLEMENTS, INJECTS, OVERRIDES, DECLARES, DECLARES_CLIENT, DECLARES_PRODUCER, CALLS, EXPOSES, HTTP_CALLS, ASYNC_CALLS; "
|
|
54
55
|
"type Symbols may also use composed neighbors edge_types DECLARES.DECLARES_CLIENT, DECLARES.DECLARES_PRODUCER, DECLARES.EXPOSES (out only, type Symbol origin). "
|
|
55
|
-
"Reprocess/init, meta, tables, diagnose-ignore, analyze-pr: use
|
|
56
|
+
"Reprocess/init, meta, tables, diagnose-ignore, analyze-pr: use jrag CLI — not MCP."
|
|
56
57
|
)
|
|
57
58
|
|
|
58
59
|
|
|
@@ -249,7 +250,7 @@ def _graph_meta_output() -> GraphMetaOutput:
|
|
|
249
250
|
success=True,
|
|
250
251
|
enabled=False,
|
|
251
252
|
db_path=resolve_ladybug_path(),
|
|
252
|
-
message="Ladybug graph not present; run
|
|
253
|
+
message="Ladybug graph not present; run jrag reprocess or build_ast_graph.py",
|
|
253
254
|
)
|
|
254
255
|
try:
|
|
255
256
|
graph = LadybugGraph.get()
|
|
@@ -480,7 +481,7 @@ async def run_refresh_pipeline(
|
|
|
480
481
|
await drop_proc.communicate()
|
|
481
482
|
except Exception as exc:
|
|
482
483
|
print(
|
|
483
|
-
f"
|
|
484
|
+
f"jrag: drop-before-reprocess failed ({exc!s}); "
|
|
484
485
|
"falling back to in-place update",
|
|
485
486
|
file=sys.stderr,
|
|
486
487
|
)
|
|
@@ -575,7 +576,7 @@ async def run_refresh_pipeline(
|
|
|
575
576
|
await optimize_lance_tables(idx_dir, quiet=quiet, on_progress=on_progress)
|
|
576
577
|
except Exception as exc:
|
|
577
578
|
optimize_error = f"lance optimize failed: {exc}"
|
|
578
|
-
print(f"
|
|
579
|
+
print(f"jrag: {optimize_error}", file=sys.stderr)
|
|
579
580
|
graph_code, graph_out, graph_err, graph_started = await _run_graph_phase(
|
|
580
581
|
root, quiet=quiet, verbose=verbose,
|
|
581
582
|
on_progress=on_progress, on_progress_console=on_progress_console,
|
|
@@ -861,6 +862,7 @@ def create_mcp_server() -> FastMCP:
|
|
|
861
862
|
|
|
862
863
|
|
|
863
864
|
def main() -> None:
|
|
865
|
+
maybe_warn_legacy_alias()
|
|
864
866
|
raise_fd_limit()
|
|
865
867
|
emit_legacy_env_hints_if_present()
|
|
866
868
|
|
java_codebase_rag/pipeline.py
CHANGED
|
@@ -24,7 +24,7 @@ COCOINDEX_TARGET = "java_index_flow_lancedb.py:JavaCodeIndexLance"
|
|
|
24
24
|
# Single source of truth — imported by cli.py (init/increment) and server.py
|
|
25
25
|
# (reprocess) so the wording can't drift between the two paths.
|
|
26
26
|
VECTORS_SKIPPED_GRAPH_ONLY = (
|
|
27
|
-
"
|
|
27
|
+
"jrag: vectors skipped — vector stack not installed on this platform "
|
|
28
28
|
"(graph-only mode). The graph is built/refreshed; semantic search is unavailable."
|
|
29
29
|
)
|
|
30
30
|
|
|
@@ -212,7 +212,7 @@ def run_cocoindex_update(
|
|
|
212
212
|
drop = run_cocoindex_drop(env, quiet=quiet)
|
|
213
213
|
if drop.returncode != 0 and not is_cocoindex_preflight_blocker(drop):
|
|
214
214
|
print(
|
|
215
|
-
"
|
|
215
|
+
"jrag: drop-before-reprocess failed "
|
|
216
216
|
f"(exit {drop.returncode}); falling back to in-place update: "
|
|
217
217
|
f"{(drop.stderr or '').strip()[:200]}",
|
|
218
218
|
file=sys.stderr,
|
|
@@ -252,7 +252,7 @@ def _maybe_run_serialized_optimize(
|
|
|
252
252
|
idx_raw = env.get("JAVA_CODEBASE_RAG_INDEX_DIR", "").strip()
|
|
253
253
|
if not idx_raw:
|
|
254
254
|
print(
|
|
255
|
-
"
|
|
255
|
+
"jrag: optimize skipped — JAVA_CODEBASE_RAG_INDEX_DIR "
|
|
256
256
|
"not set in subprocess env",
|
|
257
257
|
file=sys.stderr,
|
|
258
258
|
)
|
|
@@ -263,7 +263,7 @@ def _maybe_run_serialized_optimize(
|
|
|
263
263
|
asyncio.run(optimize_lance_tables(Path(idx_raw), quiet=quiet, on_progress=on_progress))
|
|
264
264
|
except Exception as exc:
|
|
265
265
|
# Never crash the CLI on an optimize failure — surface on stderr only.
|
|
266
|
-
print(f"
|
|
266
|
+
print(f"jrag: optimize failed: {exc}", file=sys.stderr)
|
|
267
267
|
|
|
268
268
|
|
|
269
269
|
def is_cocoindex_preflight_blocker(proc: subprocess.CompletedProcess[str]) -> bool:
|
java_codebase_rag/progress.py
CHANGED
|
@@ -300,7 +300,7 @@ def run_lexical_search(
|
|
|
300
300
|
if graph is None and not LadybugGraph.exists():
|
|
301
301
|
raise RuntimeError(
|
|
302
302
|
"lexical search unavailable: no symbol graph found; "
|
|
303
|
-
"run `
|
|
303
|
+
"run `jrag init` or `jrag reprocess` to build one"
|
|
304
304
|
)
|
|
305
305
|
g = graph or LadybugGraph.get()
|
|
306
306
|
|
|
@@ -37,7 +37,7 @@ _SYMBOL_MATCH_BONUS_CAP = 0.06
|
|
|
37
37
|
|
|
38
38
|
# Action verbs that typically mark behavioural entry points in this codebase.
|
|
39
39
|
# A chunk whose symbols begin with one of these verbs earns a small flat bump
|
|
40
|
-
# — again only for
|
|
40
|
+
# — again only for JVM (Java/Kotlin) chunks and only when role-filtering is off.
|
|
41
41
|
_ACTION_VERB_PREFIXES: tuple[str, ...] = (
|
|
42
42
|
"process", "handle", "on", "pick", "select", "assign",
|
|
43
43
|
"notify", "dispatch", "publish", "consume", "route",
|
|
@@ -64,7 +64,7 @@ _STOPWORDS: frozenset[str] = frozenset({
|
|
|
64
64
|
"may", "might", "happens", "happen", "happened", "get", "gets", "got",
|
|
65
65
|
})
|
|
66
66
|
|
|
67
|
-
# Role-aware reweighting for Java chunks. Positive values favour actionable
|
|
67
|
+
# Role-aware reweighting for Java/Kotlin chunks. Positive values favour actionable
|
|
68
68
|
# behavioural code (entrypoints, orchestrators, integrations) over configuration,
|
|
69
69
|
# schema, and persistence stubs for "what happens when..."-style queries.
|
|
70
70
|
# Applied to the similarity score (higher = better); distance-based sort subtracts
|
|
@@ -236,13 +236,27 @@ def build_fts_query(text: str) -> str:
|
|
|
236
236
|
return " ".join(out)
|
|
237
237
|
|
|
238
238
|
|
|
239
|
+
def _is_jvm_row(r: dict) -> bool:
|
|
240
|
+
"""True when a row is Java or Kotlin source (both indexed in the java table).
|
|
241
|
+
|
|
242
|
+
The additive role/bonus weighting applies to both JVM languages. Kotlin
|
|
243
|
+
chunks live in the java LanceDB table (``_kind == "java"``), but we key off
|
|
244
|
+
the semantic ``language`` field when present so detection is robust to the
|
|
245
|
+
row's table-key and any future language-keyed table split.
|
|
246
|
+
"""
|
|
247
|
+
lang = str(r.get("language") or "").lower()
|
|
248
|
+
if lang in ("java", "kotlin"):
|
|
249
|
+
return True
|
|
250
|
+
return str(r.get("_kind", "")) == "java"
|
|
251
|
+
|
|
252
|
+
|
|
239
253
|
def _symbol_bonus(r: dict, query_toks: set[str]) -> float:
|
|
240
|
-
"""Symbol-name overlap + action-verb bump for
|
|
254
|
+
"""Symbol-name overlap + action-verb bump for Java/Kotlin chunks.
|
|
241
255
|
|
|
242
256
|
Caps at `_SYMBOL_MATCH_BONUS_CAP + _ACTION_VERB_BONUS` to avoid runaway
|
|
243
257
|
ranks on chunks declaring many symbols.
|
|
244
258
|
"""
|
|
245
|
-
if
|
|
259
|
+
if not _is_jvm_row(r):
|
|
246
260
|
return 0.0
|
|
247
261
|
raw = r.get("symbols") or []
|
|
248
262
|
if isinstance(raw, str):
|
|
@@ -289,7 +303,7 @@ def _role_weight(r: dict) -> float:
|
|
|
289
303
|
cached = comps.get("role_weight")
|
|
290
304
|
if cached is not None:
|
|
291
305
|
return float(cached)
|
|
292
|
-
if r.get("_skip_role_weight") or
|
|
306
|
+
if r.get("_skip_role_weight") or not _is_jvm_row(r):
|
|
293
307
|
comps["role_weight"] = 0.0
|
|
294
308
|
return 0.0
|
|
295
309
|
role = (r.get("role") or "").upper()
|
java_codebase_rag/watch/lock.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
``ProjectLock`` is the single-writer primitive the watch daemon (Task 11)
|
|
4
4
|
acquires so that at most one watcher — and no concurrent manual
|
|
5
|
-
``
|
|
5
|
+
``jrag increment`` — runs per project.
|
|
6
6
|
|
|
7
7
|
The lock is keyed on the project's index dir: the pidfile path comes from
|
|
8
8
|
``paths.pid_path(index_dir)`` (Task 3). We hold an advisory exclusive flock on
|