java-codebase-rag 0.12.0__py3-none-any.whl → 0.12.2__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-0.12.2.dist-info/METADATA +35 -0
- java_codebase_rag-0.12.2.dist-info/RECORD +4 -0
- {java_codebase_rag-0.12.0.dist-info → java_codebase_rag-0.12.2.dist-info}/WHEEL +1 -1
- java_codebase_rag/_deprecation.py +0 -103
- java_codebase_rag/_fdlimit.py +0 -56
- java_codebase_rag/_stdio.py +0 -32
- java_codebase_rag/_version.py +0 -35
- java_codebase_rag/absence/__init__.py +0 -0
- java_codebase_rag/absence/absence_diagnosis.py +0 -700
- java_codebase_rag/absence/absence_types.py +0 -124
- java_codebase_rag/absence/absence_vocab.py +0 -460
- java_codebase_rag/analysis/__init__.py +0 -0
- java_codebase_rag/analysis/pr_analysis.py +0 -563
- java_codebase_rag/analysis/resolve_service.py +0 -740
- java_codebase_rag/ast/__init__.py +0 -0
- java_codebase_rag/ast/ast_java.py +0 -2847
- java_codebase_rag/ast/ast_kotlin.py +0 -1794
- java_codebase_rag/ast/brownfield_events.py +0 -58
- java_codebase_rag/ast/chunk_heuristics.py +0 -83
- java_codebase_rag/ast/language.py +0 -117
- java_codebase_rag/cli.py +0 -1215
- java_codebase_rag/cli_dispatch.py +0 -251
- java_codebase_rag/cli_format.py +0 -85
- java_codebase_rag/cli_progress.py +0 -94
- java_codebase_rag/config.py +0 -833
- java_codebase_rag/eval/__init__.py +0 -1
- java_codebase_rag/eval/ground_truth.py +0 -100
- java_codebase_rag/eval/metrics.py +0 -107
- java_codebase_rag/eval/runner.py +0 -556
- java_codebase_rag/graph/__init__.py +0 -0
- java_codebase_rag/graph/build_ast_graph.py +0 -4593
- java_codebase_rag/graph/graph_enrich.py +0 -1940
- java_codebase_rag/graph/graph_types.py +0 -224
- java_codebase_rag/graph/java_ontology.py +0 -465
- java_codebase_rag/graph/ladybug_queries.py +0 -2213
- java_codebase_rag/graph/path_filtering.py +0 -509
- java_codebase_rag/index/__init__.py +0 -0
- java_codebase_rag/index/java_index_flow_lancedb.py +0 -879
- java_codebase_rag/index/java_index_v1_common.py +0 -33
- java_codebase_rag/install_data/__init__.py +0 -0
- java_codebase_rag/install_data/agents/explorer-rag-cli.md +0 -110
- java_codebase_rag/install_data/agents/explorer-rag-enhanced.md +0 -152
- java_codebase_rag/install_data/skills/explore-codebase/SKILL.md +0 -165
- java_codebase_rag/install_data/skills/explore-codebase-cli/SKILL.md +0 -107
- java_codebase_rag/installer.py +0 -2188
- java_codebase_rag/jrag.py +0 -4545
- java_codebase_rag/jrag_envelope.py +0 -1107
- java_codebase_rag/jrag_hints.py +0 -204
- java_codebase_rag/jrag_render.py +0 -926
- java_codebase_rag/lance_optimize.py +0 -264
- java_codebase_rag/mcp/__init__.py +0 -0
- java_codebase_rag/mcp/mcp_hints.py +0 -932
- java_codebase_rag/mcp/mcp_v2.py +0 -1916
- java_codebase_rag/mcp/server.py +0 -886
- java_codebase_rag/pipeline.py +0 -531
- java_codebase_rag/progress.py +0 -570
- java_codebase_rag/read_payloads.py +0 -781
- java_codebase_rag/search/__init__.py +0 -0
- java_codebase_rag/search/index_common.py +0 -10
- java_codebase_rag/search/search_lancedb.py +0 -1296
- java_codebase_rag/search/search_lexical.py +0 -449
- java_codebase_rag/search/search_scoring.py +0 -537
- java_codebase_rag/watch/__init__.py +0 -0
- java_codebase_rag/watch/client.py +0 -230
- java_codebase_rag/watch/daemon.py +0 -396
- java_codebase_rag/watch/lock.py +0 -201
- java_codebase_rag/watch/paths.py +0 -76
- java_codebase_rag/watch/protocol.py +0 -122
- java_codebase_rag/watch/server.py +0 -273
- java_codebase_rag/watch/warm.py +0 -105
- java_codebase_rag/watch/watcher.py +0 -394
- java_codebase_rag-0.12.0.dist-info/METADATA +0 -340
- java_codebase_rag-0.12.0.dist-info/RECORD +0 -75
- java_codebase_rag-0.12.0.dist-info/entry_points.txt +0 -5
- java_codebase_rag-0.12.0.dist-info/licenses/LICENSE +0 -21
- java_codebase_rag-0.12.0.dist-info/top_level.txt +0 -1
- /java_codebase_rag/__init__.py → /java_codebase_rag-0.12.2.dist-info/top_level.txt +0 -0
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
"""Unified ``jrag`` CLI dispatcher (Task 2 of the rename).
|
|
2
|
-
|
|
3
|
-
The tool exposes two disjoint CLI surfaces that this module unifies behind a
|
|
4
|
-
single ``jrag`` console-script entry point:
|
|
5
|
-
|
|
6
|
-
* :mod:`java_codebase_rag.cli` — operator / lifecycle verbs (``init``,
|
|
7
|
-
``install``, ``update``, ``increment``, ``reprocess``, ``erase``, ``meta``,
|
|
8
|
-
``tables``, ``diagnose-ignore``, ``analyze-pr``, ``unresolved-calls``).
|
|
9
|
-
* :mod:`java_codebase_rag.jrag` — agent verbs (``find``, ``search``,
|
|
10
|
-
``inspect``, ``callers``, ``callees``, ``hierarchy``, ``watch``, ``status``,
|
|
11
|
-
… — 32 verbs total).
|
|
12
|
-
|
|
13
|
-
Both modules already expose a zero-argument ``_console_script_main`` that
|
|
14
|
-
reads ``sys.argv`` itself, performs its own startup (``raise_fd_limit``, UTF-8
|
|
15
|
-
stdio, error handling), and calls ``sys.exit`` (via ``os._exit``). This
|
|
16
|
-
dispatcher does NOT reimplement argparse, fd-limit, or error handling: it picks
|
|
17
|
-
the target module and forwards. Letting the chosen ``_console_script_main`` run
|
|
18
|
-
unwinds as normal, including its ``SystemExit`` / ``os._exit``.
|
|
19
|
-
|
|
20
|
-
Routing contract
|
|
21
|
-
----------------
|
|
22
|
-
For an invocation ``[argv0, *args]``:
|
|
23
|
-
|
|
24
|
-
* If any token in ``args`` is a member of :data:`OPERATOR_VERBS`, route to
|
|
25
|
-
``cli._console_script_main``.
|
|
26
|
-
* Else if any token is a member of :data:`AGENT_VERBS`, route to
|
|
27
|
-
``jrag._console_script_main``.
|
|
28
|
-
* Otherwise fall back to the identity default: the basename of ``argv0``.
|
|
29
|
-
``jrag`` → ``jrag._console_script_main``; anything else (including the
|
|
30
|
-
legacy ``java-codebase-rag`` alias) → ``cli._console_script_main``.
|
|
31
|
-
|
|
32
|
-
The "first matching verb" rule scans left-to-right and routes by *that* verb's
|
|
33
|
-
set. Operator and agent verb sets are disjoint, so the scan is unambiguous.
|
|
34
|
-
|
|
35
|
-
Known non-goal: if a global flag's value token happens to equal a verb name
|
|
36
|
-
(e.g. a hypothetical ``--config find``), routing may follow the verb heuristic.
|
|
37
|
-
Acceptable edge case — the alternative (a flag-aware parser) would duplicate
|
|
38
|
-
argparse here, which the design explicitly forbids.
|
|
39
|
-
|
|
40
|
-
Unified help contract
|
|
41
|
-
---------------------
|
|
42
|
-
For the canonical ``jrag`` identity, a top-level help request (``jrag``,
|
|
43
|
-
``jrag --help``, ``jrag -h`` — i.e. ``-h``/``--help`` appears before any
|
|
44
|
-
recognized verb, or no tokens at all) is served by :func:`_print_unified_help`:
|
|
45
|
-
it prints the agent parser's full help (agent verbs + global flags) and
|
|
46
|
-
appends a clearly labeled "Operator commands" section listing the operator
|
|
47
|
-
verbs with one-line descriptions sourced from :func:`cli.build_parser`'s
|
|
48
|
-
subparser choices. This makes ``jrag --help`` the single discovery surface for
|
|
49
|
-
all 11+32 verbs, satisfying the unification design contract.
|
|
50
|
-
|
|
51
|
-
The legacy ``java-codebase-rag`` alias does NOT get unified help: it keeps its
|
|
52
|
-
pre-rename behavior (operator-only parser) for backward compatibility, since
|
|
53
|
-
operators with shell scripts that parse ``java-codebase-rag --help`` output
|
|
54
|
-
must not see new verbs appear under that alias.
|
|
55
|
-
|
|
56
|
-
Before routing, :func:`maybe_warn_legacy_alias` runs once. It is a no-op
|
|
57
|
-
unless the tool was invoked through a legacy alias in an interactive context
|
|
58
|
-
(see :mod:`java_codebase_rag._deprecation`); in tests ``sys.stderr`` is not a
|
|
59
|
-
TTY so it stays silent.
|
|
60
|
-
"""
|
|
61
|
-
from __future__ import annotations
|
|
62
|
-
|
|
63
|
-
import argparse
|
|
64
|
-
import sys
|
|
65
|
-
from typing import Callable
|
|
66
|
-
|
|
67
|
-
from java_codebase_rag import cli as _cli_mod
|
|
68
|
-
from java_codebase_rag import jrag as _jrag_mod
|
|
69
|
-
from java_codebase_rag._deprecation import _invoked_program_name
|
|
70
|
-
from java_codebase_rag._deprecation import maybe_warn_legacy_alias
|
|
71
|
-
|
|
72
|
-
__all__ = [
|
|
73
|
-
"OPERATOR_VERBS",
|
|
74
|
-
"AGENT_VERBS",
|
|
75
|
-
"_console_script_main",
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
#: Tokens that request top-level help. argparse's default help action accepts
|
|
79
|
-
#: both ``-h`` and ``--help`` (neither parser disables ``add_help``).
|
|
80
|
-
_HELP_TOKENS: frozenset[str] = frozenset({"-h", "--help"})
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
#: Operator / lifecycle verbs. Must match ``cli.build_parser()``'s registered
|
|
84
|
-
#: top-level subcommand choice names (drift-guarded by the test suite).
|
|
85
|
-
#:
|
|
86
|
-
#: Note: the rename design spec lists ``diagnose`` and ``unresolved`` here, but
|
|
87
|
-
#: the parser actually registers ``diagnose-ignore`` and ``unresolved-calls``
|
|
88
|
-
#: (the spec abbreviated the names). The drift-guard test pins the dispatcher
|
|
89
|
-
#: to the parser's truth, so the hyphenated names are what we ship.
|
|
90
|
-
OPERATOR_VERBS: frozenset[str] = frozenset(
|
|
91
|
-
{
|
|
92
|
-
"init",
|
|
93
|
-
"install",
|
|
94
|
-
"update",
|
|
95
|
-
"increment",
|
|
96
|
-
"reprocess",
|
|
97
|
-
"erase",
|
|
98
|
-
"meta",
|
|
99
|
-
"tables",
|
|
100
|
-
"diagnose-ignore",
|
|
101
|
-
"analyze-pr",
|
|
102
|
-
"unresolved-calls",
|
|
103
|
-
}
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
#: Agent verbs. Must match ``jrag.build_parser()``'s registered top-level
|
|
107
|
-
#: subcommand choice names (drift-guarded by the test suite).
|
|
108
|
-
AGENT_VERBS: frozenset[str] = frozenset(
|
|
109
|
-
{
|
|
110
|
-
"find",
|
|
111
|
-
"search",
|
|
112
|
-
"inspect",
|
|
113
|
-
"callers",
|
|
114
|
-
"callees",
|
|
115
|
-
"hierarchy",
|
|
116
|
-
"implementations",
|
|
117
|
-
"subclasses",
|
|
118
|
-
"overrides",
|
|
119
|
-
"overridden-by",
|
|
120
|
-
"dependents",
|
|
121
|
-
"impact",
|
|
122
|
-
"decompose",
|
|
123
|
-
"flow",
|
|
124
|
-
"dependencies",
|
|
125
|
-
"connection",
|
|
126
|
-
"outline",
|
|
127
|
-
"imports",
|
|
128
|
-
"microservices",
|
|
129
|
-
"map",
|
|
130
|
-
"conventions",
|
|
131
|
-
"overview",
|
|
132
|
-
"vocab-index",
|
|
133
|
-
"watch",
|
|
134
|
-
"status",
|
|
135
|
-
"http-routes",
|
|
136
|
-
"http-clients",
|
|
137
|
-
"producers",
|
|
138
|
-
"topics",
|
|
139
|
-
"jobs",
|
|
140
|
-
"listeners",
|
|
141
|
-
"entities",
|
|
142
|
-
}
|
|
143
|
-
)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def _is_unified_help_request() -> bool:
|
|
147
|
-
"""True iff argv is a top-level help/no-args request.
|
|
148
|
-
|
|
149
|
-
Returns True when ``sys.argv[1:]`` is empty (no-args) OR contains
|
|
150
|
-
``-h``/``--help`` as the first recognized token (i.e. before any verb).
|
|
151
|
-
Returns False as soon as a verb token is seen, so verb-specific help
|
|
152
|
-
(``jrag install --help``, ``jrag find --help``) still routes to the
|
|
153
|
-
verb's own parser. Also returns False for non-help requests such as
|
|
154
|
-
``jrag --version`` (no help token, no verb — falls through to the
|
|
155
|
-
identity default).
|
|
156
|
-
"""
|
|
157
|
-
rest = sys.argv[1:] if len(sys.argv) > 1 else []
|
|
158
|
-
if not rest:
|
|
159
|
-
return True
|
|
160
|
-
for token in rest:
|
|
161
|
-
if token in OPERATOR_VERBS or token in AGENT_VERBS:
|
|
162
|
-
return False
|
|
163
|
-
if token in _HELP_TOKENS:
|
|
164
|
-
return True
|
|
165
|
-
return False
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def _operator_subcommand_helps() -> list[tuple[str, str]]:
|
|
169
|
-
"""Return ``[(verb, one_line_help), ...]`` for operator verbs, parser order.
|
|
170
|
-
|
|
171
|
-
Pulls the ``(metavar, help)`` of each ``_ChoicesPseudoAction`` registered
|
|
172
|
-
on ``cli.build_parser()``'s top-level subparsers action. Parser order
|
|
173
|
-
(lifecycle flow: ``init``, ``install``, ``update``, ...) is preserved
|
|
174
|
-
rather than sorting alphabetically.
|
|
175
|
-
"""
|
|
176
|
-
parser = _cli_mod.build_parser()
|
|
177
|
-
for action in parser._actions:
|
|
178
|
-
if isinstance(action, argparse._SubParsersAction):
|
|
179
|
-
return [(ca.metavar, ca.help or "") for ca in action._choices_actions]
|
|
180
|
-
return []
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def _print_unified_help(stream=None) -> None:
|
|
184
|
-
"""Print the canonical ``jrag`` unified help: agent verbs + operator verbs.
|
|
185
|
-
|
|
186
|
-
Prints the agent parser's full help (which already lists the 32 agent
|
|
187
|
-
verbs with one-line descriptions plus the global ``-h``/``--version``
|
|
188
|
-
options and the descriptive epilog), then appends a clearly labeled
|
|
189
|
-
"Operator commands (indexing & maintenance)" section listing the 11
|
|
190
|
-
operator verbs with their one-line descriptions sourced from
|
|
191
|
-
:func:`cli.build_parser`'s subparser choices.
|
|
192
|
-
|
|
193
|
-
Writes to ``stream`` (default ``sys.stdout``) and returns without exiting
|
|
194
|
-
— the caller (``_console_script_main``) returns to the pip wrapper, which
|
|
195
|
-
exits 0.
|
|
196
|
-
"""
|
|
197
|
-
target = stream if stream is not None else sys.stdout
|
|
198
|
-
agent_parser = _jrag_mod.build_parser()
|
|
199
|
-
agent_parser.print_help(target)
|
|
200
|
-
target.write("\n")
|
|
201
|
-
target.write(
|
|
202
|
-
"Operator commands (indexing & maintenance; run `jrag <command> --help` "
|
|
203
|
-
"for details):\n"
|
|
204
|
-
)
|
|
205
|
-
for name, help_text in _operator_subcommand_helps():
|
|
206
|
-
target.write(f" {name:<20} {help_text}\n")
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def _choose_target() -> Callable[[], None]:
|
|
210
|
-
"""Pick the ``_console_script_main`` to delegate to.
|
|
211
|
-
|
|
212
|
-
Scans ``sys.argv[1:]`` left-to-right for the first token that is a member
|
|
213
|
-
of ``OPERATOR_VERBS`` or ``AGENT_VERBS``; routes by that set. If no token
|
|
214
|
-
matches, routes by identity default (``jrag`` basename → jrag; anything
|
|
215
|
-
else → cli, including the legacy ``java-codebase-rag`` alias).
|
|
216
|
-
"""
|
|
217
|
-
rest = sys.argv[1:] if len(sys.argv) > 1 else []
|
|
218
|
-
for token in rest:
|
|
219
|
-
if token in OPERATOR_VERBS:
|
|
220
|
-
return _cli_mod._console_script_main
|
|
221
|
-
if token in AGENT_VERBS:
|
|
222
|
-
return _jrag_mod._console_script_main
|
|
223
|
-
|
|
224
|
-
# No verb token: identity default by argv[0] basename.
|
|
225
|
-
if _invoked_program_name() == "jrag":
|
|
226
|
-
return _jrag_mod._console_script_main
|
|
227
|
-
return _cli_mod._console_script_main
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def _console_script_main() -> None:
|
|
231
|
-
"""Unified ``jrag`` entry point: warn, maybe serve unified help, delegate.
|
|
232
|
-
|
|
233
|
-
For the canonical ``jrag`` identity with a top-level help/no-args request,
|
|
234
|
-
print the unified help (agent verbs + operator verbs) and return — the pip
|
|
235
|
-
wrapper then exits 0. This is the discovery surface for all verbs.
|
|
236
|
-
|
|
237
|
-
Otherwise: pick the target module and forward. The chosen target's
|
|
238
|
-
``_console_script_main`` does its own startup and terminates the process
|
|
239
|
-
(via ``os._exit``); we let ``SystemExit`` propagate rather than
|
|
240
|
-
reimplementing startup here.
|
|
241
|
-
"""
|
|
242
|
-
maybe_warn_legacy_alias()
|
|
243
|
-
if _invoked_program_name() == "jrag" and _is_unified_help_request():
|
|
244
|
-
_print_unified_help()
|
|
245
|
-
return
|
|
246
|
-
target = _choose_target()
|
|
247
|
-
target()
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if __name__ == "__main__": # pragma: no cover - direct invocation
|
|
251
|
-
_console_script_main()
|
java_codebase_rag/cli_format.py
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
"""TTY-aware ANSI formatting for CLI stderr progress."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import sys
|
|
5
|
-
|
|
6
|
-
_RESET = "\033[0m"
|
|
7
|
-
_BOLD = "\033[1m"
|
|
8
|
-
_DIM = "\033[2m"
|
|
9
|
-
_GREEN = "\033[32m"
|
|
10
|
-
_RED = "\033[31m"
|
|
11
|
-
_CYAN = "\033[36m"
|
|
12
|
-
|
|
13
|
-
CHECK = "✓"
|
|
14
|
-
CROSS = "✗"
|
|
15
|
-
|
|
16
|
-
_NOISE_CONTAINS: tuple[bytes, ...] = (
|
|
17
|
-
b"lance::",
|
|
18
|
-
b"FutureWarning",
|
|
19
|
-
b"Loading weights:",
|
|
20
|
-
b'"event": "brownfield-',
|
|
21
|
-
b"unknown producer source strategy",
|
|
22
|
-
b"unknown client source strategy",
|
|
23
|
-
# Builder verbose heartbeats / pass banners: in default mode the renderer's
|
|
24
|
-
# bar subsumes these, so they must NOT also appear as raw lines above the
|
|
25
|
-
# Live region. --verbose raw-relay bypasses this filter and still shows them.
|
|
26
|
-
b"[graph] pass ",
|
|
27
|
-
b"[graph] scoped write ",
|
|
28
|
-
b"[graph] writing ",
|
|
29
|
-
b"[graph] done ",
|
|
30
|
-
b"[increment] ",
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def is_noise_line(line: bytes) -> bool:
|
|
35
|
-
return any(p in line for p in _NOISE_CONTAINS)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def stderr_is_tty() -> bool:
|
|
39
|
-
return hasattr(sys.stderr, "isatty") and sys.stderr.isatty()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _styled(text: str, *codes: str) -> str:
|
|
43
|
-
if not stderr_is_tty():
|
|
44
|
-
return text
|
|
45
|
-
return "".join(codes) + text + _RESET
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def bold(text: str) -> str:
|
|
49
|
-
return _styled(text, _BOLD)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
def dim(text: str) -> str:
|
|
53
|
-
return _styled(text, _DIM)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def green(text: str) -> str:
|
|
57
|
-
return _styled(text, _GREEN)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def red(text: str) -> str:
|
|
61
|
-
return _styled(text, _RED)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def cyan(text: str) -> str:
|
|
65
|
-
return _styled(text, _CYAN)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
def bold_green(text: str) -> str:
|
|
69
|
-
return _styled(text, _BOLD, _GREEN)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def bold_red(text: str) -> str:
|
|
73
|
-
return _styled(text, _BOLD, _RED)
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def bold_cyan(text: str) -> str:
|
|
77
|
-
return _styled(text, _BOLD, _CYAN)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
def styled_check() -> str:
|
|
81
|
-
return green(CHECK) if stderr_is_tty() else CHECK
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def styled_cross() -> str:
|
|
85
|
-
return red(CROSS) if stderr_is_tty() else CROSS
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"""CLI-owned stderr progress lines (shared by server reprocess path and pipeline helpers)."""
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import asyncio
|
|
5
|
-
import sys
|
|
6
|
-
from typing import Callable
|
|
7
|
-
|
|
8
|
-
from java_codebase_rag.cli_format import is_noise_line
|
|
9
|
-
from java_codebase_rag.progress import ProgressEvent, make_relay
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class _AsyncLineFilter:
|
|
13
|
-
"""Buffers byte chunks and relays only non-noise lines to stderr (async drain path)."""
|
|
14
|
-
|
|
15
|
-
def __init__(self) -> None:
|
|
16
|
-
self._buf = bytearray()
|
|
17
|
-
self._suppress_next = False
|
|
18
|
-
|
|
19
|
-
def feed(self, chunk: bytes) -> None:
|
|
20
|
-
self._buf.extend(chunk)
|
|
21
|
-
while b"\n" in self._buf:
|
|
22
|
-
line, self._buf = self._buf.split(b"\n", 1)
|
|
23
|
-
line += b"\n"
|
|
24
|
-
noise = is_noise_line(line)
|
|
25
|
-
if noise:
|
|
26
|
-
self._suppress_next = True
|
|
27
|
-
continue
|
|
28
|
-
if self._suppress_next and line[:1] in (b" ", b"\t"):
|
|
29
|
-
continue
|
|
30
|
-
self._suppress_next = False
|
|
31
|
-
sys.stderr.buffer.write(line)
|
|
32
|
-
sys.stderr.buffer.flush()
|
|
33
|
-
|
|
34
|
-
def flush(self) -> None:
|
|
35
|
-
if self._buf:
|
|
36
|
-
if not is_noise_line(self._buf):
|
|
37
|
-
sys.stderr.buffer.write(bytes(self._buf))
|
|
38
|
-
sys.stderr.buffer.flush()
|
|
39
|
-
self._buf.clear()
|
|
40
|
-
self._suppress_next = False
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
async def accumulate_and_relay_subprocess_streams(
|
|
44
|
-
proc: asyncio.subprocess.Process,
|
|
45
|
-
*,
|
|
46
|
-
relay: bool,
|
|
47
|
-
verbose: bool = True,
|
|
48
|
-
on_progress: Callable[[ProgressEvent], None] | None = None,
|
|
49
|
-
on_progress_console: object | None = None,
|
|
50
|
-
) -> tuple[bytes, bytes]:
|
|
51
|
-
"""Read stdout and stderr until EOF; optionally copy non-noise stderr chunks to stderr.
|
|
52
|
-
|
|
53
|
-
When ``on_progress`` is set, stderr is drained through a :class:`ProgressRelay`
|
|
54
|
-
so ``JCIRAG_PROGRESS`` lines are parsed and routed to ``on_progress`` (and
|
|
55
|
-
suppressed from the relay), matching the sync ``pipeline._popen_capturing_stderr``.
|
|
56
|
-
"""
|
|
57
|
-
stdout = proc.stdout
|
|
58
|
-
stderr = proc.stderr
|
|
59
|
-
if stdout is None or stderr is None:
|
|
60
|
-
raise RuntimeError("subprocess must be created with stdout=PIPE and stderr=PIPE")
|
|
61
|
-
|
|
62
|
-
out_buf = bytearray()
|
|
63
|
-
err_buf = bytearray()
|
|
64
|
-
if on_progress is not None:
|
|
65
|
-
filt = make_relay(on_progress, console=on_progress_console, verbose=verbose)
|
|
66
|
-
elif relay and not verbose:
|
|
67
|
-
filt = _AsyncLineFilter()
|
|
68
|
-
else:
|
|
69
|
-
filt = None
|
|
70
|
-
|
|
71
|
-
async def drain_stdout(reader: asyncio.StreamReader, target: bytearray) -> None:
|
|
72
|
-
while True:
|
|
73
|
-
chunk = await reader.read(65536)
|
|
74
|
-
if not chunk:
|
|
75
|
-
break
|
|
76
|
-
target.extend(chunk)
|
|
77
|
-
|
|
78
|
-
async def drain_stderr(reader: asyncio.StreamReader, target: bytearray) -> None:
|
|
79
|
-
while True:
|
|
80
|
-
chunk = await reader.read(65536)
|
|
81
|
-
if not chunk:
|
|
82
|
-
break
|
|
83
|
-
target.extend(chunk)
|
|
84
|
-
if filt is not None:
|
|
85
|
-
filt.feed(chunk)
|
|
86
|
-
elif relay:
|
|
87
|
-
sys.stderr.buffer.write(chunk)
|
|
88
|
-
sys.stderr.buffer.flush()
|
|
89
|
-
|
|
90
|
-
await asyncio.gather(drain_stdout(stdout, out_buf), drain_stderr(stderr, err_buf))
|
|
91
|
-
await proc.wait()
|
|
92
|
-
if filt is not None:
|
|
93
|
-
filt.flush()
|
|
94
|
-
return bytes(out_buf), bytes(err_buf)
|