java-codebase-rag 0.6.2__py3-none-any.whl → 0.6.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ast_java.py +28 -57
- build_ast_graph.py +118 -26
- graph_enrich.py +13 -35
- java_codebase_rag/cli.py +97 -24
- java_codebase_rag/cli_format.py +8 -35
- java_codebase_rag/cli_progress.py +17 -21
- java_codebase_rag/install_data/agents/explorer-rag-enhanced.md +3 -3
- java_codebase_rag/install_data/skills/explore-codebase/SKILL.md +5 -5
- java_codebase_rag/installer.py +180 -43
- java_codebase_rag/lance_optimize.py +125 -51
- java_codebase_rag/pipeline.py +71 -23
- java_codebase_rag/progress.py +570 -0
- {java_codebase_rag-0.6.2.dist-info → java_codebase_rag-0.6.4.dist-info}/METADATA +13 -10
- java_codebase_rag-0.6.4.dist-info/RECORD +34 -0
- java_index_flow_lancedb.py +238 -18
- ladybug_queries.py +45 -51
- mcp_v2.py +9 -17
- path_filtering.py +14 -17
- pr_analysis.py +3 -4
- search_lancedb.py +2 -2
- server.py +75 -9
- java_codebase_rag-0.6.2.dist-info/RECORD +0 -33
- {java_codebase_rag-0.6.2.dist-info → java_codebase_rag-0.6.4.dist-info}/WHEEL +0 -0
- {java_codebase_rag-0.6.2.dist-info → java_codebase_rag-0.6.4.dist-info}/entry_points.txt +0 -0
- {java_codebase_rag-0.6.2.dist-info → java_codebase_rag-0.6.4.dist-info}/licenses/LICENSE +0 -0
- {java_codebase_rag-0.6.2.dist-info → java_codebase_rag-0.6.4.dist-info}/top_level.txt +0 -0
java_codebase_rag/installer.py
CHANGED
|
@@ -14,6 +14,7 @@ import os
|
|
|
14
14
|
import shutil
|
|
15
15
|
import sys
|
|
16
16
|
import tempfile
|
|
17
|
+
import time
|
|
17
18
|
from dataclasses import dataclass
|
|
18
19
|
from pathlib import Path
|
|
19
20
|
from typing import Literal, NamedTuple
|
|
@@ -806,6 +807,38 @@ def update_gitignore(cwd: Path) -> None:
|
|
|
806
807
|
gitignore_path.write_text("\n".join(lines), encoding="utf-8")
|
|
807
808
|
|
|
808
809
|
|
|
810
|
+
def _index_progress_header(subcommand: str, source_root: Path, index_dir: Path) -> None:
|
|
811
|
+
"""Print the stderr header framing the indexing sub-step (install/update).
|
|
812
|
+
|
|
813
|
+
Mirrors the operator commands' ``_pipeline_header`` but lives in the
|
|
814
|
+
installer because the wizard's stdout framing differs. This brackets ONLY
|
|
815
|
+
the indexing sub-step — the wizard's prompts stay outside it on stdout.
|
|
816
|
+
"""
|
|
817
|
+
from java_codebase_rag.cli_format import bold
|
|
818
|
+
|
|
819
|
+
print(
|
|
820
|
+
bold(
|
|
821
|
+
f"java-codebase-rag {subcommand} · source={source_root.resolve()} "
|
|
822
|
+
f"· index={index_dir.resolve()}"
|
|
823
|
+
),
|
|
824
|
+
file=sys.stderr,
|
|
825
|
+
flush=True,
|
|
826
|
+
)
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
def _index_progress_footer(subcommand: str, started: float, *, ok: bool) -> None:
|
|
830
|
+
"""Print the stderr footer closing the indexing sub-step framing."""
|
|
831
|
+
from java_codebase_rag.cli_format import bold, styled_check, styled_cross
|
|
832
|
+
|
|
833
|
+
elapsed = time.perf_counter() - started
|
|
834
|
+
marker = styled_check() if ok else styled_cross()
|
|
835
|
+
print(
|
|
836
|
+
f"{marker} {bold(f'java-codebase-rag {subcommand} · finished in {elapsed:.2f}s')}",
|
|
837
|
+
file=sys.stderr,
|
|
838
|
+
flush=True,
|
|
839
|
+
)
|
|
840
|
+
|
|
841
|
+
|
|
809
842
|
def run_init_if_needed(
|
|
810
843
|
source_root: Path,
|
|
811
844
|
index_dir: Path,
|
|
@@ -813,15 +846,25 @@ def run_init_if_needed(
|
|
|
813
846
|
*,
|
|
814
847
|
non_interactive: bool,
|
|
815
848
|
quiet: bool,
|
|
849
|
+
verbose: bool = False,
|
|
816
850
|
) -> bool:
|
|
817
851
|
"""Run init if index directory has no artifacts. Return True if init was run.
|
|
818
852
|
|
|
853
|
+
The indexing sub-step (CocoIndex update + AST graph build) renders the
|
|
854
|
+
unified ``Vectors → Optimize → Graph`` progress on **stderr** in default
|
|
855
|
+
mode (same renderer the operator commands use); the wizard's conversational
|
|
856
|
+
stdout is untouched by this function. ``--quiet`` is silent; ``--verbose``
|
|
857
|
+
raw-relays subprocess output. The indexing chatter that used to print to
|
|
858
|
+
stdout (``Creating index…`` / ``Index created successfully.``) now lives
|
|
859
|
+
on stderr framing so stdout stays the wizard payload.
|
|
860
|
+
|
|
819
861
|
Args:
|
|
820
862
|
source_root: Source root directory
|
|
821
863
|
index_dir: Index directory path
|
|
822
864
|
model: Embedding model path or "auto"
|
|
823
865
|
non_interactive: If True, suppress prompts
|
|
824
|
-
quiet: If True, suppress output
|
|
866
|
+
quiet: If True, suppress progress output
|
|
867
|
+
verbose: If True, raw-relay subprocess output (no Live region)
|
|
825
868
|
|
|
826
869
|
Returns:
|
|
827
870
|
True if init was run, False if skipped
|
|
@@ -837,36 +880,71 @@ def run_init_if_needed(
|
|
|
837
880
|
print("Index already exists. Run `java-codebase-rag reprocess` to rebuild.")
|
|
838
881
|
return False
|
|
839
882
|
|
|
840
|
-
print("Creating index...")
|
|
841
883
|
cfg = resolve_operator_config(
|
|
842
884
|
source_root=source_root,
|
|
843
885
|
cli_index_dir=None, # use default (<source_root>/.java-codebase-rag)
|
|
844
886
|
cli_embedding_model=model if model != "auto" else None,
|
|
845
887
|
)
|
|
846
888
|
cfg.apply_to_os_environ()
|
|
847
|
-
|
|
848
889
|
env = cfg.subprocess_env()
|
|
849
890
|
|
|
850
|
-
#
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
891
|
+
# Indexing sub-step: render unified progress on stderr in default mode only
|
|
892
|
+
# (quiet = silent; verbose = raw relay, no Live region). The renderer wraps
|
|
893
|
+
# just this sub-step, not the surrounding wizard.
|
|
894
|
+
on_progress, on_progress_console = None, None
|
|
895
|
+
renderer = None
|
|
896
|
+
if not quiet and not verbose:
|
|
897
|
+
from java_codebase_rag.progress import build_index_progress_context
|
|
898
|
+
|
|
899
|
+
renderer, on_progress, on_progress_console = build_index_progress_context()
|
|
900
|
+
|
|
901
|
+
started = time.perf_counter()
|
|
902
|
+
if renderer is not None:
|
|
903
|
+
_index_progress_header("install", cfg.source_root, cfg.index_dir)
|
|
904
|
+
renderer.start()
|
|
905
|
+
index_ok = True
|
|
906
|
+
try:
|
|
907
|
+
coco = run_cocoindex_update(
|
|
908
|
+
env,
|
|
909
|
+
full_reprocess=False,
|
|
910
|
+
quiet=quiet,
|
|
911
|
+
verbose=verbose,
|
|
912
|
+
on_progress=on_progress,
|
|
913
|
+
on_progress_console=on_progress_console,
|
|
914
|
+
)
|
|
915
|
+
if coco.returncode != 0:
|
|
916
|
+
print(
|
|
917
|
+
f"Error: CocoIndex update failed with code {coco.returncode}",
|
|
918
|
+
file=sys.stderr,
|
|
919
|
+
)
|
|
920
|
+
index_ok = False
|
|
921
|
+
else:
|
|
922
|
+
g = run_build_ast_graph(
|
|
923
|
+
source_root=cfg.source_root,
|
|
924
|
+
ladybug_path=cfg.ladybug_path,
|
|
925
|
+
verbose=verbose,
|
|
926
|
+
quiet=quiet,
|
|
927
|
+
env=env,
|
|
928
|
+
on_progress=on_progress,
|
|
929
|
+
on_progress_console=on_progress_console,
|
|
930
|
+
)
|
|
931
|
+
if g.returncode != 0:
|
|
932
|
+
print(
|
|
933
|
+
f"Error: AST graph build failed with code {g.returncode}",
|
|
934
|
+
file=sys.stderr,
|
|
935
|
+
)
|
|
936
|
+
index_ok = False
|
|
937
|
+
except BaseException:
|
|
938
|
+
# An exception from cocoindex/graph means the index did not succeed;
|
|
939
|
+
# flip the footer marker before re-raising so it renders a red cross
|
|
940
|
+
# (mirrors cli._run_with_pipeline_progress's BaseException handler).
|
|
941
|
+
index_ok = False
|
|
942
|
+
raise
|
|
943
|
+
finally:
|
|
944
|
+
if renderer is not None:
|
|
945
|
+
renderer.stop()
|
|
946
|
+
_index_progress_footer("install", started, ok=index_ok)
|
|
947
|
+
return index_ok
|
|
870
948
|
|
|
871
949
|
|
|
872
950
|
def handle_rerun(cwd: Path, *, non_interactive: bool) -> dict | None:
|
|
@@ -1201,13 +1279,25 @@ def run_update(
|
|
|
1201
1279
|
force: bool,
|
|
1202
1280
|
dry_run: bool,
|
|
1203
1281
|
cwd: Path | None = None,
|
|
1282
|
+
quiet: bool = False,
|
|
1283
|
+
verbose: bool = False,
|
|
1204
1284
|
) -> int:
|
|
1205
1285
|
"""Run the update pipeline. Returns exit code.
|
|
1206
1286
|
|
|
1287
|
+
The indexing sub-step (Lance catch-up + incremental graph) renders the
|
|
1288
|
+
unified ``Vectors → Optimize → Graph`` progress on **stderr** in default
|
|
1289
|
+
mode and no longer runs with ``quiet=True`` (the reason ``update`` was
|
|
1290
|
+
silent). ``--quiet`` is silent; ``--verbose`` raw-relays subprocess output.
|
|
1291
|
+
The wizard's host-detection / refresh / summary stdout is preserved; only
|
|
1292
|
+
the indexing chatter that used to print to stdout moves onto the stderr
|
|
1293
|
+
renderer framing.
|
|
1294
|
+
|
|
1207
1295
|
Args:
|
|
1208
1296
|
force: If True, overwrite all artifacts even if matching
|
|
1209
1297
|
dry_run: If True, print changes without writing
|
|
1210
1298
|
cwd: Current working directory (defaults to Path.cwd())
|
|
1299
|
+
quiet: If True, suppress progress output
|
|
1300
|
+
verbose: If True, raw-relay subprocess output (no Live region)
|
|
1211
1301
|
|
|
1212
1302
|
Returns:
|
|
1213
1303
|
Exit code (0=success, 1=partial, 2=fatal)
|
|
@@ -1282,30 +1372,74 @@ def run_update(
|
|
|
1282
1372
|
# The "graph not implemented" warning belongs only on the vectors-only path
|
|
1283
1373
|
# (increment --vectors-only), where the graph step is deliberately skipped.
|
|
1284
1374
|
if not dry_run:
|
|
1285
|
-
print("\nUpdating index (Lance + graph)...")
|
|
1286
1375
|
cfg.apply_to_os_environ()
|
|
1287
1376
|
env = cfg.subprocess_env()
|
|
1288
1377
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
)
|
|
1301
|
-
if
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1378
|
+
# Indexing sub-step: render unified progress on stderr in default mode
|
|
1379
|
+
# only (quiet = silent; verbose = raw relay). No longer runs quiet=True
|
|
1380
|
+
# — that was why `update` was silent. The renderer wraps just this
|
|
1381
|
+
# sub-step; the wizard's summary stdout below is outside it.
|
|
1382
|
+
on_progress, on_progress_console = None, None
|
|
1383
|
+
renderer = None
|
|
1384
|
+
if not quiet and not verbose:
|
|
1385
|
+
from java_codebase_rag.progress import build_index_progress_context
|
|
1386
|
+
|
|
1387
|
+
renderer, on_progress, on_progress_console = build_index_progress_context()
|
|
1388
|
+
|
|
1389
|
+
started = time.perf_counter()
|
|
1390
|
+
if renderer is not None:
|
|
1391
|
+
_index_progress_header("update", cfg.source_root, cfg.index_dir)
|
|
1392
|
+
renderer.start()
|
|
1393
|
+
index_ok = True
|
|
1394
|
+
try:
|
|
1395
|
+
coco = run_cocoindex_update(
|
|
1396
|
+
env,
|
|
1397
|
+
full_reprocess=False,
|
|
1398
|
+
quiet=quiet,
|
|
1399
|
+
verbose=verbose,
|
|
1400
|
+
on_progress=on_progress,
|
|
1401
|
+
on_progress_console=on_progress_console,
|
|
1308
1402
|
)
|
|
1403
|
+
if coco.returncode != 0:
|
|
1404
|
+
print(
|
|
1405
|
+
f"Error: Lance index update failed with code {coco.returncode}",
|
|
1406
|
+
file=sys.stderr,
|
|
1407
|
+
)
|
|
1408
|
+
index_ok = False
|
|
1409
|
+
else:
|
|
1410
|
+
g = run_incremental_graph(
|
|
1411
|
+
source_root=cfg.source_root,
|
|
1412
|
+
ladybug_path=cfg.ladybug_path,
|
|
1413
|
+
verbose=verbose,
|
|
1414
|
+
quiet=quiet,
|
|
1415
|
+
env=env,
|
|
1416
|
+
on_progress=on_progress,
|
|
1417
|
+
on_progress_console=on_progress_console,
|
|
1418
|
+
)
|
|
1419
|
+
if g.returncode != 0:
|
|
1420
|
+
# The graph catch-up is best-effort: `update`'s primary job
|
|
1421
|
+
# is refreshing shipped artifacts + vectors (cocoindex). A
|
|
1422
|
+
# graph failure surfaces a truthful, actionable Warning on
|
|
1423
|
+
# stderr but does NOT flip index_ok (which drives both the
|
|
1424
|
+
# footer marker and the return code) — exit 0 with a green
|
|
1425
|
+
# check + the Warning line carrying the graph caveat.
|
|
1426
|
+
print(
|
|
1427
|
+
f"\nWarning: incremental graph update failed (exit {g.returncode}). "
|
|
1428
|
+
"Run `java-codebase-rag reprocess` for a full rebuild.",
|
|
1429
|
+
file=sys.stderr,
|
|
1430
|
+
)
|
|
1431
|
+
except BaseException:
|
|
1432
|
+
# An exception from cocoindex/graph means the index did not succeed;
|
|
1433
|
+
# flip the footer marker before re-raising so it renders a red cross
|
|
1434
|
+
# (mirrors cli._run_with_pipeline_progress's BaseException handler).
|
|
1435
|
+
index_ok = False
|
|
1436
|
+
raise
|
|
1437
|
+
finally:
|
|
1438
|
+
if renderer is not None:
|
|
1439
|
+
renderer.stop()
|
|
1440
|
+
_index_progress_footer("update", started, ok=index_ok)
|
|
1441
|
+
if not index_ok:
|
|
1442
|
+
return 1
|
|
1309
1443
|
else:
|
|
1310
1444
|
print("\nWould run incremental index update (Lance + graph).")
|
|
1311
1445
|
|
|
@@ -1325,6 +1459,7 @@ def run_install(
|
|
|
1325
1459
|
model: str | None,
|
|
1326
1460
|
source_root: Path | None = None,
|
|
1327
1461
|
quiet: bool = False,
|
|
1462
|
+
verbose: bool = False,
|
|
1328
1463
|
) -> int:
|
|
1329
1464
|
"""Run the install pipeline. Returns exit code.
|
|
1330
1465
|
|
|
@@ -1335,6 +1470,7 @@ def run_install(
|
|
|
1335
1470
|
model: Model from CLI flag
|
|
1336
1471
|
source_root: Source root path (defaults to cwd if None)
|
|
1337
1472
|
quiet: If True, suppress output
|
|
1473
|
+
verbose: If True, raw-relay subprocess indexing output (no Live region)
|
|
1338
1474
|
|
|
1339
1475
|
Returns:
|
|
1340
1476
|
Exit code (0=success, 1=partial, 2=fatal)
|
|
@@ -1433,6 +1569,7 @@ def run_install(
|
|
|
1433
1569
|
resolved_model,
|
|
1434
1570
|
non_interactive=non_interactive,
|
|
1435
1571
|
quiet=quiet,
|
|
1572
|
+
verbose=verbose,
|
|
1436
1573
|
)
|
|
1437
1574
|
|
|
1438
1575
|
return 0
|
|
@@ -21,7 +21,14 @@ from __future__ import annotations
|
|
|
21
21
|
|
|
22
22
|
import asyncio
|
|
23
23
|
import sys
|
|
24
|
+
import time
|
|
24
25
|
from pathlib import Path
|
|
26
|
+
from typing import Callable, Literal
|
|
27
|
+
|
|
28
|
+
# Mirrors ``ProgressStatus`` in ``progress.py``; kept local (rather than imported)
|
|
29
|
+
# so this module never pays the ``rich`` cost at import time — see
|
|
30
|
+
# ``_make_optimize_event``.
|
|
31
|
+
_OptimizeStatus = Literal["running", "done", "failed"]
|
|
25
32
|
|
|
26
33
|
# Single source of truth for the three Lance table names created by the flow.
|
|
27
34
|
# Keep in sync with ``search_lancedb.TABLES`` (the values there mirror these).
|
|
@@ -31,6 +38,33 @@ LANCE_TABLE_NAMES: tuple[str, ...] = (
|
|
|
31
38
|
"yamlconfigindex_yaml_config",
|
|
32
39
|
)
|
|
33
40
|
|
|
41
|
+
|
|
42
|
+
def _make_optimize_event(
|
|
43
|
+
*,
|
|
44
|
+
status: _OptimizeStatus,
|
|
45
|
+
elapsed_s: float | None = None,
|
|
46
|
+
):
|
|
47
|
+
"""Build a ``ProgressEvent(kind="optimize", …)`` lazily (progress is parent-side).
|
|
48
|
+
|
|
49
|
+
``lance_optimize`` runs in-process in the parent (called by
|
|
50
|
+
``pipeline._maybe_run_serialized_optimize`` and
|
|
51
|
+
``server.run_refresh_pipeline``); it routes progress to the renderer via the
|
|
52
|
+
in-process ``on_progress`` callback — NOT via stderr (which would corrupt
|
|
53
|
+
the Live region). The import is local so the flow (which imports
|
|
54
|
+
``LANCE_TABLE_NAMES`` at definition time) never pays the ``rich`` cost.
|
|
55
|
+
"""
|
|
56
|
+
from java_codebase_rag.progress import ProgressEvent
|
|
57
|
+
|
|
58
|
+
return ProgressEvent(
|
|
59
|
+
kind="optimize",
|
|
60
|
+
phase=None,
|
|
61
|
+
pass_=None,
|
|
62
|
+
done=None,
|
|
63
|
+
total=None,
|
|
64
|
+
status=status,
|
|
65
|
+
elapsed_s=elapsed_s,
|
|
66
|
+
)
|
|
67
|
+
|
|
34
68
|
# Commit conflicts are transient; a handful of exponential-backoff retries is
|
|
35
69
|
# enough because, post-flow, there are no concurrent writers — only successive
|
|
36
70
|
# optimize/compaction passes within this single serialized call can still
|
|
@@ -60,7 +94,12 @@ async def _list_table_names(db: object) -> set[str]:
|
|
|
60
94
|
return set(await db.table_names())
|
|
61
95
|
|
|
62
96
|
|
|
63
|
-
async def optimize_lance_tables(
|
|
97
|
+
async def optimize_lance_tables(
|
|
98
|
+
index_dir: Path,
|
|
99
|
+
*,
|
|
100
|
+
quiet: bool = False,
|
|
101
|
+
on_progress: Callable | None = None,
|
|
102
|
+
) -> dict[str, str]:
|
|
64
103
|
"""Optimize all known Lance tables under *index_dir*, serially, with retry.
|
|
65
104
|
|
|
66
105
|
Runs ``table.optimize()`` for each name in :data:`LANCE_TABLE_NAMES` that
|
|
@@ -73,6 +112,13 @@ async def optimize_lance_tables(index_dir: Path, *, quiet: bool = False) -> dict
|
|
|
73
112
|
index_dir: directory holding the Lance tables (the flow's LanceDB URI).
|
|
74
113
|
quiet: when True, suppress the per-table success/skip info lines on
|
|
75
114
|
stderr (errors are always logged).
|
|
115
|
+
on_progress: optional in-process progress callback (the parent's
|
|
116
|
+
renderer ``on_progress``). When given, emits
|
|
117
|
+
``ProgressEvent(kind="optimize", status="running")`` on entry and a
|
|
118
|
+
terminal ``status="done"``/``"failed"`` event on exit (covers BOTH
|
|
119
|
+
call sites: ``pipeline._maybe_run_serialized_optimize`` and
|
|
120
|
+
``server.run_refresh_pipeline``). In-process only — NEVER prints to
|
|
121
|
+
stderr (that would corrupt the Live region).
|
|
76
122
|
|
|
77
123
|
Returns:
|
|
78
124
|
Mapping of table name → status. Values are ``"ok"``, ``"skipped"``
|
|
@@ -82,67 +128,95 @@ async def optimize_lance_tables(index_dir: Path, *, quiet: bool = False) -> dict
|
|
|
82
128
|
# not pay the lancedb import cost at flow-definition time.
|
|
83
129
|
import lancedb
|
|
84
130
|
|
|
131
|
+
if on_progress is not None:
|
|
132
|
+
on_progress(_make_optimize_event(status="running"))
|
|
133
|
+
t0 = time.perf_counter()
|
|
85
134
|
results: dict[str, str] = {}
|
|
86
|
-
|
|
135
|
+
failed = False
|
|
87
136
|
try:
|
|
137
|
+
db = await lancedb.connect_async(str(index_dir))
|
|
88
138
|
try:
|
|
89
|
-
existing = await _list_table_names(db)
|
|
90
|
-
except Exception as exc:
|
|
91
|
-
print(
|
|
92
|
-
f"java-codebase-rag: optimize: failed to list tables in "
|
|
93
|
-
f"{index_dir}: {exc}",
|
|
94
|
-
file=sys.stderr,
|
|
95
|
-
)
|
|
96
|
-
return {name: f"error: list failed: {exc}" for name in LANCE_TABLE_NAMES}
|
|
97
|
-
|
|
98
|
-
for name in LANCE_TABLE_NAMES:
|
|
99
|
-
if name not in existing:
|
|
100
|
-
results[name] = "skipped"
|
|
101
|
-
if not quiet:
|
|
102
|
-
print(
|
|
103
|
-
f"java-codebase-rag: optimize: {name} absent, skipped",
|
|
104
|
-
file=sys.stderr,
|
|
105
|
-
)
|
|
106
|
-
continue
|
|
107
139
|
try:
|
|
108
|
-
|
|
140
|
+
existing = await _list_table_names(db)
|
|
109
141
|
except Exception as exc:
|
|
110
|
-
results[name] = f"error: open failed: {exc}"
|
|
111
142
|
print(
|
|
112
|
-
f"java-codebase-rag: optimize:
|
|
143
|
+
f"java-codebase-rag: optimize: failed to list tables in "
|
|
144
|
+
f"{index_dir}: {exc}",
|
|
113
145
|
file=sys.stderr,
|
|
114
146
|
)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
for
|
|
147
|
+
failed = True
|
|
148
|
+
return {name: f"error: list failed: {exc}" for name in LANCE_TABLE_NAMES}
|
|
149
|
+
|
|
150
|
+
for name in LANCE_TABLE_NAMES:
|
|
151
|
+
if name not in existing:
|
|
152
|
+
results[name] = "skipped"
|
|
153
|
+
if not quiet:
|
|
154
|
+
print(
|
|
155
|
+
f"java-codebase-rag: optimize: {name} absent, skipped",
|
|
156
|
+
file=sys.stderr,
|
|
157
|
+
)
|
|
158
|
+
continue
|
|
119
159
|
try:
|
|
120
|
-
await
|
|
121
|
-
last_exc = None
|
|
122
|
-
break
|
|
160
|
+
table = await db.open_table(name)
|
|
123
161
|
except Exception as exc:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
await asyncio.sleep(_BASE_BACKOFF_S * (2**attempt))
|
|
127
|
-
continue
|
|
128
|
-
# Non-retryable, or retries exhausted: stop the loop and
|
|
129
|
-
# surface below — do not swallow silently.
|
|
130
|
-
break
|
|
131
|
-
|
|
132
|
-
if last_exc is None:
|
|
133
|
-
results[name] = "ok"
|
|
134
|
-
if not quiet:
|
|
162
|
+
results[name] = f"error: open failed: {exc}"
|
|
163
|
+
failed = True
|
|
135
164
|
print(
|
|
136
|
-
f"java-codebase-rag: optimize: {name}
|
|
165
|
+
f"java-codebase-rag: optimize: {name} open failed: {exc}",
|
|
137
166
|
file=sys.stderr,
|
|
138
167
|
)
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
168
|
+
continue
|
|
169
|
+
|
|
170
|
+
last_exc: BaseException | None = None
|
|
171
|
+
for attempt in range(_MAX_ATTEMPTS):
|
|
172
|
+
try:
|
|
173
|
+
await table.optimize()
|
|
174
|
+
last_exc = None
|
|
175
|
+
break
|
|
176
|
+
except Exception as exc:
|
|
177
|
+
last_exc = exc
|
|
178
|
+
if _is_retryable(exc) and attempt < _MAX_ATTEMPTS - 1:
|
|
179
|
+
await asyncio.sleep(_BASE_BACKOFF_S * (2**attempt))
|
|
180
|
+
continue
|
|
181
|
+
# Non-retryable, or retries exhausted: stop the loop and
|
|
182
|
+
# surface below — do not swallow silently.
|
|
183
|
+
break
|
|
184
|
+
|
|
185
|
+
if last_exc is None:
|
|
186
|
+
results[name] = "ok"
|
|
187
|
+
if not quiet:
|
|
188
|
+
print(
|
|
189
|
+
f"java-codebase-rag: optimize: {name} ok",
|
|
190
|
+
file=sys.stderr,
|
|
191
|
+
)
|
|
192
|
+
else:
|
|
193
|
+
results[name] = f"error: {last_exc}"
|
|
194
|
+
failed = True
|
|
195
|
+
print(
|
|
196
|
+
f"java-codebase-rag: optimize: {name} failed: {last_exc}",
|
|
197
|
+
file=sys.stderr,
|
|
198
|
+
)
|
|
199
|
+
finally:
|
|
200
|
+
# ``AsyncConnection.close`` is a *sync* method in lancedb 0.30.x.
|
|
201
|
+
db.close()
|
|
202
|
+
return results
|
|
203
|
+
except Exception:
|
|
204
|
+
# An unexpected exception (e.g. ``connect_async`` raised, or a table-
|
|
205
|
+
# independent failure) must still flip the terminal event to failed so
|
|
206
|
+
# the renderer's task doesn't render a green check on a crash. Re-raise
|
|
207
|
+
# after marking — the caller (``_maybe_run_serialized_optimize`` /
|
|
208
|
+
# ``run_refresh_pipeline``) treats optimize failure as non-fatal and
|
|
209
|
+
# logs it, but the renderer must reflect the truth.
|
|
210
|
+
failed = True
|
|
211
|
+
raise
|
|
145
212
|
finally:
|
|
146
|
-
#
|
|
147
|
-
|
|
148
|
-
|
|
213
|
+
# Always emit a terminal optimize event so the renderer's task never
|
|
214
|
+
# hangs at "running" — even on exception (the parent treats a failed
|
|
215
|
+
# optimize as non-fatal: the index is still searchable un-compacted).
|
|
216
|
+
if on_progress is not None:
|
|
217
|
+
on_progress(
|
|
218
|
+
_make_optimize_event(
|
|
219
|
+
status="failed" if failed else "done",
|
|
220
|
+
elapsed_s=time.perf_counter() - t0,
|
|
221
|
+
)
|
|
222
|
+
)
|