java-codebase-rag 0.9.4__py3-none-any.whl → 0.9.5__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.
server.py CHANGED
@@ -10,10 +10,12 @@ from pathlib import Path
10
10
  from typing import Literal
11
11
 
12
12
  import mcp_v2
13
+ import resolve_service
13
14
  from index_common import SBERT_MODEL
14
15
  from java_codebase_rag.cli_progress import (
15
16
  accumulate_and_relay_subprocess_streams,
16
17
  )
18
+ from java_codebase_rag.pipeline import VECTORS_SKIPPED_GRAPH_ONLY, vector_stack_installed
17
19
  from java_codebase_rag.progress import ProgressEvent
18
20
  from java_codebase_rag._fdlimit import raise_fd_limit
19
21
  from java_codebase_rag.config import (
@@ -314,6 +316,61 @@ def list_code_index_tables_payload() -> IndexInfoOutput:
314
316
  )
315
317
 
316
318
 
319
+ async def _run_graph_phase(
320
+ root: Path,
321
+ *,
322
+ quiet: bool,
323
+ verbose: bool,
324
+ on_progress: object | None,
325
+ on_progress_console: object | None,
326
+ ) -> tuple[int | None, str, str, bool]:
327
+ """Run ``build_ast_graph.py`` and return ``(code, stdout, stderr, started)``.
328
+
329
+ Shared by the vectors→graph refresh path and the graph-only path (macOS Intel,
330
+ where the vector stack is gated off). ``started`` is True only when the graph
331
+ subprocess was actually created, so callers set ``phases_run`` accurately — the
332
+ CLI maps an empty ``phases_run`` to a preflight exit code 2 (nothing spawned).
333
+ A missing builder or a spawn failure returns ``started=False`` with the graph
334
+ code carrying the reason (``None`` for missing builder, ``-1`` for spawn error).
335
+ """
336
+ builder = Path(__file__).resolve().parent / "build_ast_graph.py"
337
+ if not builder.is_file():
338
+ return None, "", "", False
339
+ try:
340
+ graph_args = [
341
+ sys.executable,
342
+ str(builder),
343
+ "--source-root",
344
+ str(root),
345
+ "--ladybug-path",
346
+ resolve_ladybug_path(),
347
+ ]
348
+ if not quiet:
349
+ graph_args.append("--verbose")
350
+ gproc = await asyncio.create_subprocess_exec(
351
+ *graph_args,
352
+ cwd=str(root),
353
+ env=_cocoindex_subprocess_env(root),
354
+ stdout=asyncio.subprocess.PIPE,
355
+ stderr=asyncio.subprocess.PIPE,
356
+ )
357
+ if quiet:
358
+ gout_b, gerr_b = await gproc.communicate()
359
+ else:
360
+ gout_b, gerr_b = await accumulate_and_relay_subprocess_streams(
361
+ gproc, relay=True, verbose=verbose,
362
+ on_progress=on_progress, on_progress_console=on_progress_console,
363
+ )
364
+ return (
365
+ gproc.returncode,
366
+ gout_b.decode(errors="replace"),
367
+ gerr_b.decode(errors="replace"),
368
+ True,
369
+ )
370
+ except Exception as exc:
371
+ return -1, "", f"graph builder spawn failed: {exc}", False
372
+
373
+
317
374
  async def run_refresh_pipeline(
318
375
  *,
319
376
  quiet: bool = False,
@@ -322,6 +379,42 @@ async def run_refresh_pipeline(
322
379
  on_progress_console: object | None = None,
323
380
  ) -> RefreshIndexOutput:
324
381
  root = _project_root()
382
+ if not vector_stack_installed():
383
+ # Graph-only install (macOS Intel): the vector stack (cocoindex/lancedb/
384
+ # sentence-transformers) is gated off by PEP 508 markers and uninstallable,
385
+ # so the cocoindex binary is absent. Skip the vectors phase and build the
386
+ # graph only — mirroring init/increment, which treat cocoindex-absent as a
387
+ # skip, not a failure (the graph layer is the supported surface there). No
388
+ # vectors progress event is emitted, so the renderer's vectors task stays
389
+ # invisible (its "never spawned" invariant) instead of hanging at running.
390
+ print(VECTORS_SKIPPED_GRAPH_ONLY, file=sys.stderr, flush=True)
391
+ if not quiet:
392
+ print(file=sys.stderr, flush=True)
393
+ graph_code, graph_out, graph_err, started = await _run_graph_phase(
394
+ root, quiet=quiet, verbose=verbose,
395
+ on_progress=on_progress, on_progress_console=on_progress_console,
396
+ )
397
+ ok = graph_code == 0
398
+ if not ok:
399
+ message = (
400
+ f"graph builder exit {graph_code}"
401
+ if graph_code is not None
402
+ else (graph_err.strip() or "graph builder unavailable")
403
+ )
404
+ else:
405
+ message = "reprocess completed (graph-only; vectors skipped — vector stack not installed)"
406
+ return RefreshIndexOutput(
407
+ success=ok,
408
+ exit_code=None,
409
+ stdout="",
410
+ stderr="",
411
+ message=message,
412
+ graph_exit_code=graph_code,
413
+ graph_stdout=graph_out[-4000:] if len(graph_out) > 4000 else graph_out,
414
+ graph_stderr=graph_err[-4000:] if len(graph_err) > 4000 else graph_err,
415
+ phases_run=["graph"] if started else [],
416
+ optimize_error=None,
417
+ )
325
418
  cocoindex_bin = Path(sys.executable).parent / "cocoindex"
326
419
  if not cocoindex_bin.is_file():
327
420
  # 127 pre-spawn: emit a terminal failed vectors event so the renderer's
@@ -466,40 +559,12 @@ async def run_refresh_pipeline(
466
559
  except Exception as exc:
467
560
  optimize_error = f"lance optimize failed: {exc}"
468
561
  print(f"java-codebase-rag: {optimize_error}", file=sys.stderr)
469
- builder = Path(__file__).resolve().parent / "build_ast_graph.py"
470
- if builder.is_file():
471
- try:
472
- graph_args = [
473
- sys.executable,
474
- str(builder),
475
- "--source-root",
476
- str(root),
477
- "--ladybug-path",
478
- resolve_ladybug_path(),
479
- ]
480
- if not quiet:
481
- graph_args.append("--verbose")
482
- gproc = await asyncio.create_subprocess_exec(
483
- *graph_args,
484
- cwd=str(root),
485
- env=_cocoindex_subprocess_env(root),
486
- stdout=asyncio.subprocess.PIPE,
487
- stderr=asyncio.subprocess.PIPE,
488
- )
489
- phases_run = ["vectors", "graph"]
490
- if quiet:
491
- gout_b, gerr_b = await gproc.communicate()
492
- else:
493
- gout_b, gerr_b = await accumulate_and_relay_subprocess_streams(
494
- gproc, relay=True, verbose=verbose,
495
- on_progress=on_progress, on_progress_console=on_progress_console,
496
- )
497
- graph_code = gproc.returncode
498
- graph_out = gout_b.decode(errors="replace")
499
- graph_err = gerr_b.decode(errors="replace")
500
- except Exception as exc:
501
- graph_code = -1
502
- graph_err = f"graph builder spawn failed: {exc}"
562
+ graph_code, graph_out, graph_err, graph_started = await _run_graph_phase(
563
+ root, quiet=quiet, verbose=verbose,
564
+ on_progress=on_progress, on_progress_console=on_progress_console,
565
+ )
566
+ if graph_started:
567
+ phases_run = ["vectors", "graph"]
503
568
  message: str | None = None
504
569
  if not ok:
505
570
  message = f"cocoindex exit {proc.returncode}"
@@ -788,6 +853,8 @@ def main() -> None:
788
853
  cfg = resolve_operator_config(source_root=_source_root_for_operator_config())
789
854
  cfg.apply_to_os_environ()
790
855
  mcp_v2.set_hints_enabled(cfg.hints_enabled)
856
+ mcp_v2.set_absence_config(cfg)
857
+ resolve_service.set_absence_config(cfg)
791
858
 
792
859
  # Initialize scope manager for automatic microservice detection
793
860
  global _scope_manager