better-code-review-graph 3.26.26__tar.gz → 3.27.0__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.
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.claude-plugin/plugin.json +1 -1
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/CHANGELOG.md +27 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/PKG-INFO +2 -3
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/versions/005_temporal_columns.py +44 -1
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/pyproject.toml +9 -17
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/server.json +2 -2
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/cli.py +59 -17
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/config.py +33 -0
- better_code_review_graph-3.27.0/src/better_code_review_graph/credential_state.py +160 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/embeddings.py +138 -174
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/server.py +85 -160
- better_code_review_graph-3.27.0/src/better_code_review_graph/summarizer.py +290 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/tools.py +6 -11
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/conftest.py +22 -27
- better_code_review_graph-3.27.0/tests/integration/test_multi_user_remote.py +72 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_cohere_dimensions.py +49 -45
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_coverage_gaps.py +65 -54
- better_code_review_graph-3.27.0/tests/test_credential_state_dehosted.py +114 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_crg_protocol_harness.py +0 -1
- better_code_review_graph-3.27.0/tests/test_embedder_retry_classification.py +130 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_embeddings.py +339 -159
- better_code_review_graph-3.27.0/tests/test_g6_ux_status_accuracy.py +120 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_oci_publication_sunset.py +15 -2
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_parser_source_text.py +27 -7
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_server.py +7 -7
- better_code_review_graph-3.27.0/tests/test_setup_tool.py +197 -0
- better_code_review_graph-3.27.0/tests/test_summarizer.py +468 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_temporal_migration.py +57 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_v17_coverage_gaps.py +8 -7
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/uv.lock +16 -489
- better_code_review_graph-3.26.26/src/better_code_review_graph/credential_state.py +0 -363
- better_code_review_graph-3.26.26/src/better_code_review_graph/relay_schema.py +0 -133
- better_code_review_graph-3.26.26/src/better_code_review_graph/relay_setup.py +0 -150
- better_code_review_graph-3.26.26/src/better_code_review_graph/summarizer.py +0 -325
- better_code_review_graph-3.26.26/tests/integration/test_multi_user_remote.py +0 -43
- better_code_review_graph-3.26.26/tests/test_config_open_relay_registered.py +0 -66
- better_code_review_graph-3.26.26/tests/test_credential_state.py +0 -435
- better_code_review_graph-3.26.26/tests/test_credential_state_stdio_no_fallback.py +0 -210
- better_code_review_graph-3.26.26/tests/test_credential_state_store_errors.py +0 -164
- better_code_review_graph-3.26.26/tests/test_embedder_retry_classification.py +0 -139
- better_code_review_graph-3.26.26/tests/test_g6_ux_status_accuracy.py +0 -120
- better_code_review_graph-3.26.26/tests/test_home_isolation.py +0 -113
- better_code_review_graph-3.26.26/tests/test_multi_user.py +0 -181
- better_code_review_graph-3.26.26/tests/test_multi_user_dispatch.py +0 -513
- better_code_review_graph-3.26.26/tests/test_per_plugin_storage_migration.py +0 -38
- better_code_review_graph-3.26.26/tests/test_relay_schema.py +0 -56
- better_code_review_graph-3.26.26/tests/test_relay_setup.py +0 -365
- better_code_review_graph-3.26.26/tests/test_setup_tool.py +0 -312
- better_code_review_graph-3.26.26/tests/test_summarizer.py +0 -967
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.agents/skills/build-graph/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.agents/skills/review-delta/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.agents/skills/review-pr/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.coderabbit.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.dockerignore +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/CODEOWNERS +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/review-learnings.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/rulesets/main.json +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/workflows/cd.yml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.github/workflows/ci.yml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.gitignore +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.infisical.json +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.jules/bolt.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.jules/sentinel.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.pre-commit-config.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/AGENTS.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/BREAKING_CHANGES.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/CLAUDE.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/CODE_OF_CONDUCT.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/CONTRIBUTING.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/Dockerfile +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/LICENSE +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/LICENSE-MIT +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/NOTICE +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/README.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/SECURITY.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/alembic.ini +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/docs/HANDOVER.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/hooks/_graph_state.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/hooks/branch-sync-check.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/hooks/hooks.json +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/hooks/stale-graph-check.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/README +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/env.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/script.py.mako +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/versions/001_baseline.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/versions/002_summary_columns.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/versions/003_federation.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/versions/004_security_tags.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/migrations/versions/006_commits_table.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/renovate.json +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/rules/heuristic/cwe-22-path-traversal.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/rules/heuristic/cwe-78-shell-command-sink.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/rules/heuristic/cwe-89-sql-string-format.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/rules/heuristic/cwe-95-eval-on-input.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/rules/heuristic/hardcoded-secret.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/rules/semgrep/curated.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/scripts/benchmark_row_deserialization.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/scripts/enforce-commit.sh +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/scripts/preserve-diacritics.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/scripts/test_preserve_diacritics.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/semantic-release.toml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/skills/impact-audit/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/skills/onboard-repo/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/skills/refactor-check/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/skills/review-delta/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/skills/review-pr/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/skills/security-sweep/SKILL.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/smithery.yaml +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/__init__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/__main__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/__init__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/config.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/graph.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/query.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/recipes.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/review.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/docs/security.md +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/exporter.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/federation.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/graph.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/importer.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/incremental.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/parser.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/py.typed +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/reranker.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/__init__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/_types.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/fallback.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/go.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/java.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/python.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/rust.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/resolver/typescript.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/security/__init__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/security/heuristic.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/security/semgrep_engine.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/temporal.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/src/better_code_review_graph/xpia.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/__init__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/conftest_e2e.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/e2e_mcp_protocol_test.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/Sample.cs +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/SampleJava.java +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/callback_refs.js +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/caller_example.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/multi_call_example.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.c +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.cpp +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.kt +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.php +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.rb +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.sol +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample.swift +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample_go.go +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample_python.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample_rust.rs +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/sample_typescript.ts +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/fixtures/test_sample.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/integration/__init__.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_alembic_baseline.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_as_of_diff.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_auto_resolve_ambiguity.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_bare_suffix_correctness.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_callers_not_found_reason.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_callers_of_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_cli.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_cli_contracts.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_commits_migration.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_custom_local_model.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_dynamic_dispatch_hints.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_e2e.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_embedding_migration.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_embeddings_extra.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_export_graph_dispatch.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_export_graph_dispatch_path_traversal.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_exporter.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_federation.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_federation_migration.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_federation_smoke.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_full_live.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_get_docs_section_error_path.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_get_review_context_no_diff.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_graph.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_graph_batch_fetch.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_graph_extra.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_graph_get_edges_by_targets_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_graph_stats_error_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_handle_not_found_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_help_recipes.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_heuristic.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_impact_payload_truncation.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_implements_edges.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_import_graph_dispatch.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_importer.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_incremental.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_incremental_extra.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_kind_filter_optimization.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_kinds_error_path.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_list_graph_stats_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_list_kinds_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_live_mcp.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_local_reranker.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_lookup_node_directly.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_multilang.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_no_stale_package_name.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_oserror_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_parser.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_parser_extra.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_parser_grammar_failure.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_path_resolution_fallback.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_payload_estimation.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_per_sub_graph_db.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_performance_n1.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_performance_n1_embeddings.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_phase_3_smoke.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_plugin_assets.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_pre_2_0_backup.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_renamed_in_diff.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_renamed_in_diff_exception.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_repo_filter.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_repo_filter_batching.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_repo_id_persistence.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolve_search_candidates.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_dispatcher.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_fallback.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_go.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_java.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_python.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_rust.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_resolver_typescript.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_response_header.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_response_payload_honesty.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_review_delta_line_shifts.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_review_languages_filter.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_reviewer_summary.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_search_edges_by_target_names.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_search_keyword_warning.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_security_injection.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_security_path_traversal.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_security_scan_batching.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_security_tags_migration.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_security_tool.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_semgrep_engine.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_server_help_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_serverinfo_version.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_shares_state_edges.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_spot_check.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_sql_security.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_stdio_direct.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_summarize_graph_dispatch.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_summary_schema.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_temporal.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_tested_by_edges.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_tools.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_tools_build_error_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_tools_full.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_tools_get_docs_section_coverage.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_typescript_coverage_gaps.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_xpia.py +0 -0
- {better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/tests/test_xpia_adversarial.py +0 -0
{better_code_review_graph-3.26.26 → better_code_review_graph-3.27.0}/.claude-plugin/plugin.json
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-code-review-graph",
|
|
3
3
|
"description": "Knowledge graph for token-efficient code reviews -- semantic search and call-graph resolution across your codebase.",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.27.0",
|
|
5
5
|
"userConfig": {
|
|
6
6
|
"EMBEDDING_MODELS": {
|
|
7
7
|
"type": "string",
|
|
@@ -2,6 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v3.27.0 (2026-09-26)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **migrations**: 005 skip git guard for per-subject data-dir stores
|
|
10
|
+
([`5944956`](https://github.com/n24q02m/crg/commit/5944956259acd70ce76d02dd160587dbb9fa832c))
|
|
11
|
+
|
|
12
|
+
- **server**: Drop dead _maybe_include_setup_hint hook (BYOK cut residual)
|
|
13
|
+
([`87c9ce4`](https://github.com/n24q02m/crg/commit/87c9ce454501aaa2ec39373f3731739ae7247054))
|
|
14
|
+
|
|
15
|
+
- **server,tools**: Remove deleted-member imports on search/setup/http paths
|
|
16
|
+
([`edc7b5f`](https://github.com/n24q02m/crg/commit/edc7b5f24d61bd1cf8eec1089396e269750694ab))
|
|
17
|
+
|
|
18
|
+
- **wp2**: Drop mcp-core entirely; port residual tests to hull seams
|
|
19
|
+
([`91b1ddb`](https://github.com/n24q02m/crg/commit/91b1ddb20ca4957ef32bbf40b478c01a8419a5a7))
|
|
20
|
+
|
|
21
|
+
### Features
|
|
22
|
+
|
|
23
|
+
- **wp2**: De-host onto hull-core — auth scoping, model cells, config bridge
|
|
24
|
+
([`0683c62`](https://github.com/n24q02m/crg/commit/0683c62d88fbaf11aa8666a3adcf21cd357c9a63))
|
|
25
|
+
|
|
26
|
+
### Testing
|
|
27
|
+
|
|
28
|
+
- Port suite to the post-de-host surface (hull cells, no litellm/relay)
|
|
29
|
+
([`fd7795d`](https://github.com/n24q02m/crg/commit/fd7795da0f3ac268430e5d22cbef4756a2120f0d))
|
|
30
|
+
|
|
31
|
+
|
|
5
32
|
## v3.26.26 (2026-09-25)
|
|
6
33
|
|
|
7
34
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: better-code-review-graph
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.27.0
|
|
4
4
|
Summary: Token-efficient code review knowledge graph: semantic search and call-graph resolution.
|
|
5
5
|
Author: n24q02m
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -18,9 +18,8 @@ Requires-Dist: defusedxml>=0.7.1
|
|
|
18
18
|
Requires-Dist: fastmcp<4,>=3.4.7
|
|
19
19
|
Requires-Dist: fastretrieval<2,>=1.8.2
|
|
20
20
|
Requires-Dist: httpx
|
|
21
|
-
Requires-Dist:
|
|
21
|
+
Requires-Dist: hull-core
|
|
22
22
|
Requires-Dist: mcp<2,>=1.30.0
|
|
23
|
-
Requires-Dist: n24q02m-mcp-core[llm]==1.24.6
|
|
24
23
|
Requires-Dist: networkx<4,>=3.7
|
|
25
24
|
Requires-Dist: pydantic-settings
|
|
26
25
|
Requires-Dist: pygments>=2.21.0
|
|
@@ -118,6 +118,15 @@ _SHA_RE = re.compile(r"^[0-9a-f]{40}$|^[0-9a-f]{64}$")
|
|
|
118
118
|
# git-init its own tmp dir, which conflicts with tests that
|
|
119
119
|
# construct ``tmp_path / ".git"`` themselves.
|
|
120
120
|
#
|
|
121
|
+
# 3. The DB is a per-subject store under the crg data directory
|
|
122
|
+
# (``<CRG_DATA_DIR>/subs/<sub>/graph.db``, ``~/.crg`` default).
|
|
123
|
+
# Multi-user (hull mode-3) deployments scope each namespace's
|
|
124
|
+
# graph to its own data-directory DB precisely so it does NOT
|
|
125
|
+
# live inside any analyzed repo — there is no single HEAD to
|
|
126
|
+
# backfill with, so the sentinel is the correct value. Repo
|
|
127
|
+
# stores (``<repo>/.better-code-review-graph/graph.db``) still
|
|
128
|
+
# require git.
|
|
129
|
+
#
|
|
121
130
|
# Production code paths leave ``CRG_TEST_ALLOW_NO_GIT`` unset, so the
|
|
122
131
|
# migration still aborts with the actionable :class:`RuntimeError`
|
|
123
132
|
# whenever a file-backed DB has no reachable repo — production data
|
|
@@ -152,6 +161,35 @@ def _extract_db_path_from_url(url: str) -> Path | None:
|
|
|
152
161
|
return Path(raw).resolve()
|
|
153
162
|
|
|
154
163
|
|
|
164
|
+
def _data_dir_subs_base() -> Path:
|
|
165
|
+
"""Return the resolved ``subs`` root of the crg data directory.
|
|
166
|
+
|
|
167
|
+
Mirrors ``credential_state._sub_data_dir``: ``$CRG_DATA_DIR`` when
|
|
168
|
+
set, otherwise ``~/.crg``. Per-subject stores (multi-user HTTP
|
|
169
|
+
mode) live at ``<base>/subs/<sub>/graph.db`` under this root.
|
|
170
|
+
"""
|
|
171
|
+
base = Path(os.environ.get("CRG_DATA_DIR", str(Path.home() / ".crg")))
|
|
172
|
+
return (base / "subs").resolve()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def _is_data_dir_store(db_path: Path) -> bool:
|
|
176
|
+
"""True iff ``db_path`` is a per-subject store under the crg data dir.
|
|
177
|
+
|
|
178
|
+
Multi-user (hull mode-3) deployments scope each namespace's graph to
|
|
179
|
+
``<CRG_DATA_DIR>/subs/<sub>/graph.db`` — a data-directory DB that
|
|
180
|
+
intentionally does NOT live inside any analyzed repo (the analyzed
|
|
181
|
+
repo directory is not a safe shared location for a per-tenant DB).
|
|
182
|
+
Such a store has no single HEAD to backfill ``valid_from_sha``
|
|
183
|
+
with, so the 40-zero sentinel applies. Repo stores
|
|
184
|
+
(``<repo>/.better-code-review-graph/graph.db``) keep the hard git
|
|
185
|
+
requirement enforced by :func:`_find_repo_root`.
|
|
186
|
+
"""
|
|
187
|
+
try:
|
|
188
|
+
return db_path.resolve().is_relative_to(_data_dir_subs_base())
|
|
189
|
+
except (OSError, ValueError):
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
|
|
155
193
|
def _find_repo_root(db_path: Path) -> Path:
|
|
156
194
|
"""Walk parents of ``db_path`` looking for a ``.git`` entry.
|
|
157
195
|
|
|
@@ -291,7 +329,10 @@ def _resolve_head_sha() -> str:
|
|
|
291
329
|
process so the value is only the DDL default for transient tests, OR
|
|
292
330
|
* the file-backed DB has no reachable ``.git`` ancestor AND the
|
|
293
331
|
operator has opted in to the test-only escape hatch via
|
|
294
|
-
``CRG_TEST_ALLOW_NO_GIT=1
|
|
332
|
+
``CRG_TEST_ALLOW_NO_GIT=1``, OR
|
|
333
|
+
* the DB is a per-subject store under the crg data directory
|
|
334
|
+
(``<CRG_DATA_DIR>/subs/<sub>/graph.db``) — a data-directory DB
|
|
335
|
+
intentionally outside every repo, so there is no HEAD to read.
|
|
295
336
|
|
|
296
337
|
File-backed DBs without a reachable ``.git`` ancestor and without
|
|
297
338
|
the test escape hatch still raise the actionable
|
|
@@ -307,6 +348,8 @@ def _resolve_head_sha() -> str:
|
|
|
307
348
|
db_path = _extract_db_path_from_url(url)
|
|
308
349
|
if db_path is None:
|
|
309
350
|
return _IN_MEMORY_SENTINEL_SHA
|
|
351
|
+
if _is_data_dir_store(db_path):
|
|
352
|
+
return _IN_MEMORY_SENTINEL_SHA
|
|
310
353
|
try:
|
|
311
354
|
repo_root = _find_repo_root(db_path)
|
|
312
355
|
return _read_head_sha(repo_root)
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "better-code-review-graph"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.27.0"
|
|
8
8
|
description = "Token-efficient code review knowledge graph: semantic search and call-graph resolution."
|
|
9
9
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -27,27 +27,19 @@ dependencies = [
|
|
|
27
27
|
"fastretrieval>=1.8.2,<2",
|
|
28
28
|
"httpx",
|
|
29
29
|
"pydantic-settings",
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
# sorts below its own stable under PEP 440 and does not require it.
|
|
36
|
-
"n24q02m-mcp-core[llm]==1.24.6",
|
|
37
|
-
# litellm security floor (transitive via mcp-core[llm]). 1.83.x-1.87.x carry 4
|
|
38
|
-
# advisories in litellm's PROXY server: GHSA-r75f-5x8p-qvmc (SQLi in proxy key
|
|
39
|
-
# verify), GHSA-xqmj-j6mv-4862 (SSTI /prompts/test), GHSA-v4p8-mg3p-g94g (cmd-exec
|
|
40
|
-
# proxy MCP endpoints), GHSA-wxxx-gvqv-xp7p (sandbox escape custom-code guardrail).
|
|
41
|
-
# We use litellm LIBRARY mode only (no proxy) so none are in our attack surface,
|
|
42
|
-
# but Dependency Review flags the package version. 1.88.0+ clears all four.
|
|
43
|
-
# crg's optional semgrep extra otherwise pins the resolver to litellm 1.83.0; this
|
|
44
|
-
# floor lifts it (semgrep resolves to 1.79.x, fine for a dev-only SAST tool).
|
|
45
|
-
"litellm>=1.102.0",
|
|
30
|
+
# De-hosted shared core (WP1): token auth (3 modes), per-task model cells
|
|
31
|
+
# (plain-HTTP OpenAI-spec, no litellm), server lifecycle lock. Vendored via
|
|
32
|
+
# git because hull-core is not published to PyPI (spec 2026-09-26 §3);
|
|
33
|
+
# rev pins the WP1-verified hull commit.
|
|
34
|
+
"hull-core",
|
|
46
35
|
"Pygments>=2.21.0",
|
|
47
36
|
"alembic>=1.20.0,<2",
|
|
48
37
|
"defusedxml>=0.7.1",
|
|
49
38
|
]
|
|
50
39
|
|
|
40
|
+
[tool.uv.sources]
|
|
41
|
+
hull-core = { git = "https://github.com/n24q02m/hull", subdirectory = "packages/core-py", rev = "5262d54f4f0c1214dcedaef20531da98f9519bdf" }
|
|
42
|
+
|
|
51
43
|
[project.scripts]
|
|
52
44
|
better-code-review-graph = "better_code_review_graph.cli:main"
|
|
53
45
|
crg = "better_code_review_graph.cli:main"
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/n24q02m/crg.git",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.27.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "pypi",
|
|
13
13
|
"identifier": "better-code-review-graph",
|
|
14
|
-
"version": "3.
|
|
14
|
+
"version": "3.27.0",
|
|
15
15
|
"runtimeHint": "uvx",
|
|
16
16
|
"runtimeArgs": [
|
|
17
17
|
"--python",
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
"""Console-script entry:
|
|
1
|
+
"""Console-script entry: local argparse dispatch (de-hosted, no shared core).
|
|
2
2
|
|
|
3
|
-
Bare invocation and any leading-dash argv (e.g. --http) start the server
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Bare invocation and any leading-dash argv (e.g. --http) start the server;
|
|
4
|
+
a leading positional argv[0] routes to a subcommand (``graph``, ``query``,
|
|
5
|
+
``review``, ``security``) instead of the server.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
@@ -519,19 +519,61 @@ def _handle_security(args: argparse.Namespace) -> int:
|
|
|
519
519
|
|
|
520
520
|
|
|
521
521
|
def main() -> int:
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
522
|
+
"""Route argv: server start vs. local subcommands.
|
|
523
|
+
|
|
524
|
+
Same dispatch contract the shared core builder used to provide, now
|
|
525
|
+
local: bare or leading-dash argv goes to the server (``_serve``), a
|
|
526
|
+
known leading subcommand is parsed by its own argparse subparser and
|
|
527
|
+
handed to its handler, anything else is a clean rc-2 usage error.
|
|
528
|
+
"""
|
|
529
|
+
import sys
|
|
530
|
+
|
|
531
|
+
handlers: dict[str, tuple[Any, Any]] = {
|
|
532
|
+
"graph": (_configure_graph, _handle_graph),
|
|
533
|
+
"query": (_configure_query, _handle_query),
|
|
534
|
+
"review": (_configure_review, _handle_review),
|
|
535
|
+
"security": (_configure_security, _handle_security),
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
argv = sys.argv[1:]
|
|
539
|
+
if not argv:
|
|
540
|
+
rc = _serve([])
|
|
541
|
+
return 0 if rc is None else rc
|
|
542
|
+
|
|
543
|
+
# Intercept bare flags before argparse: -h/--help/--version must print
|
|
544
|
+
# and exit instead of starting (and blocking on) the stdio server, and
|
|
545
|
+
# any other leading dash is passed through to the server untouched.
|
|
546
|
+
if argv[0] in ("-h", "--help"):
|
|
547
|
+
names = ", ".join(sorted(handlers))
|
|
548
|
+
print("usage: better-code-review-graph [-h] [--version] [<subcommand> ...]")
|
|
549
|
+
print("Any other flags/args are passed through to the MCP server (e.g. --http).")
|
|
550
|
+
print(f"subcommands: {names}")
|
|
551
|
+
return 0
|
|
552
|
+
if argv[0] in ("--version", "-V"):
|
|
553
|
+
print(f"better-code-review-graph {_version()}")
|
|
554
|
+
return 0
|
|
555
|
+
if argv[0].startswith("-"):
|
|
556
|
+
rc = _serve(argv)
|
|
557
|
+
return 0 if rc is None else rc
|
|
558
|
+
|
|
559
|
+
spec = handlers.get(argv[0])
|
|
560
|
+
if spec is None:
|
|
561
|
+
names = ", ".join(sorted(handlers))
|
|
562
|
+
print(
|
|
563
|
+
f"better-code-review-graph: unknown subcommand {argv[0]!r} "
|
|
564
|
+
f"(expected one of: {names})",
|
|
565
|
+
file=sys.stderr,
|
|
566
|
+
)
|
|
567
|
+
return 2
|
|
568
|
+
|
|
569
|
+
configure_fn, handler_fn = spec
|
|
570
|
+
parser = argparse.ArgumentParser(prog="better-code-review-graph")
|
|
571
|
+
subparsers = parser.add_subparsers(dest="subcommand")
|
|
572
|
+
sub = subparsers.add_parser(argv[0])
|
|
573
|
+
if configure_fn is not None:
|
|
574
|
+
configure_fn(sub)
|
|
575
|
+
ns = parser.parse_args(argv)
|
|
576
|
+
return handler_fn(ns)
|
|
535
577
|
|
|
536
578
|
|
|
537
579
|
if __name__ == "__main__":
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"""Cấu hình cho backend embedding cục bộ của CRG."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
3
5
|
from typing import Any
|
|
4
6
|
|
|
7
|
+
from hull_core.config.models import ModelCell, resolve_model_cells
|
|
8
|
+
from hull_core.config.settings import HullSettings, load_settings
|
|
5
9
|
from pydantic import model_validator
|
|
6
10
|
from pydantic_settings import BaseSettings
|
|
7
11
|
|
|
@@ -44,3 +48,32 @@ class Settings(BaseSettings):
|
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
settings = Settings()
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ---------------------------------------------------------------------------
|
|
54
|
+
# Hull-core instance config (WP2 de-host, spec 2026-09-26 §3/§4)
|
|
55
|
+
# ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def crg_config_dir() -> Path:
|
|
59
|
+
"""Host-owned instance config directory: ``$CRG_CONFIG_DIR`` or ``~/.crg``.
|
|
60
|
+
|
|
61
|
+
Same schema as hull's ``config.toml``: ``[server]`` (bind, auth mode,
|
|
62
|
+
users file) + per-task ``[models.<task>]`` provider cells. Keys live
|
|
63
|
+
here (or arrive via ``HULL_<TASK>_API_KEY`` env) — they are host-only
|
|
64
|
+
material and never end-user supplied (spec §4 Q1, BYOK cut).
|
|
65
|
+
"""
|
|
66
|
+
return Path(os.environ.get("CRG_CONFIG_DIR") or Path.home() / ".crg")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def load_instance_settings() -> HullSettings:
|
|
70
|
+
"""Load the crg instance config through hull-core's loader."""
|
|
71
|
+
return load_settings(crg_config_dir())
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def resolve_cells(
|
|
75
|
+
settings: HullSettings | None = None, env: dict[str, str] | None = None
|
|
76
|
+
) -> dict[str, ModelCell]:
|
|
77
|
+
"""Resolve the per-task provider cells (embed / rerank / chat / jev_score)."""
|
|
78
|
+
settings = settings if settings is not None else load_instance_settings()
|
|
79
|
+
return resolve_model_cells(settings.models, env=env)
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Per-request subject scoping and per-sub data paths.
|
|
2
|
+
|
|
3
|
+
De-hosted (WP2, spec 2026-09-26 §4): authentication is hull-core's token
|
|
4
|
+
middleware with three config modes (no-auth / token / multi, ``users.toml``).
|
|
5
|
+
There is no credential store, no browser setup flow, and no per-user key
|
|
6
|
+
bucket —
|
|
7
|
+
provider keys are host-only material configured in the instance
|
|
8
|
+
``config.toml`` ``[models.*]`` cells (or ``HULL_<TASK>_API_KEY`` env); the
|
|
9
|
+
end user never sees or submits them (BYOK cut).
|
|
10
|
+
|
|
11
|
+
What remains here is the data-isolation half: in auth mode ``multi`` the
|
|
12
|
+
authenticated user's namespace scopes the graph database at
|
|
13
|
+
``subs/<namespace>/graph.db`` under ``CRG_DATA_DIR`` so concurrent users on
|
|
14
|
+
one process never see each other's graph. Modes no-auth/token keep one
|
|
15
|
+
shared namespace and therefore the repo-local ``graph.db`` (same file the
|
|
16
|
+
CLI uses — host indexing and serving stay consistent).
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import contextvars
|
|
22
|
+
import logging
|
|
23
|
+
import os
|
|
24
|
+
from enum import Enum
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
|
|
27
|
+
logger = logging.getLogger(__name__)
|
|
28
|
+
|
|
29
|
+
SERVER_NAME = "better-code-review-graph"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CredentialState(Enum):
|
|
33
|
+
CONFIGURED = "configured" # at least one per-task model cell has a key
|
|
34
|
+
LOCAL = "local" # no cloud cells configured; local ONNX fallback serves
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Module-level state (host-level; never per-request — per-request identity
|
|
38
|
+
# flows exclusively through the contextvars below).
|
|
39
|
+
_state: CredentialState = CredentialState.LOCAL
|
|
40
|
+
|
|
41
|
+
# Per-request namespace subject (HTTP multi-user mode).
|
|
42
|
+
#
|
|
43
|
+
# Bound by the hull auth middleware's resolved identity: tool handlers call
|
|
44
|
+
# :func:`get_current_sub`, which prefers an explicit :func:`set_current_sub`
|
|
45
|
+
# binding and otherwise falls back to hull-core's ``current_user()``
|
|
46
|
+
# contextvar when the request authenticated in ``multi`` mode. ``None`` in
|
|
47
|
+
# stdio mode, the CLI, and single-namespace HTTP modes (no-auth/token) —
|
|
48
|
+
# those share the repo-local graph.db.
|
|
49
|
+
_current_sub: contextvars.ContextVar[str | None] = contextvars.ContextVar(
|
|
50
|
+
"crg_current_sub", default=None
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_state() -> CredentialState:
|
|
55
|
+
"""Return current credential state."""
|
|
56
|
+
return _state
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def resolve_credential_state() -> CredentialState:
|
|
60
|
+
"""Resolve whether any per-task model cell is configured (has a key).
|
|
61
|
+
|
|
62
|
+
Host-only check against the instance ``config.toml`` cells + key env
|
|
63
|
+
vars. Local ONNX embedding and everything except cloud summarize/embed
|
|
64
|
+
work regardless, so ``LOCAL`` is a valid steady state, not an error.
|
|
65
|
+
Takes <10ms; called during HTTP lifespan startup and by ``config``.
|
|
66
|
+
"""
|
|
67
|
+
global _state
|
|
68
|
+
|
|
69
|
+
from .config import resolve_cells
|
|
70
|
+
|
|
71
|
+
cells = resolve_cells()
|
|
72
|
+
configured = any(cell.configured for cell in cells.values())
|
|
73
|
+
_state = CredentialState.CONFIGURED if configured else CredentialState.LOCAL
|
|
74
|
+
logger.info("Credential state resolved: %s", _state.value)
|
|
75
|
+
return _state
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def set_state(state: CredentialState) -> None:
|
|
79
|
+
"""For testing and the config tool status action."""
|
|
80
|
+
global _state
|
|
81
|
+
_state = state
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _sub_data_dir(sub: str) -> Path:
|
|
85
|
+
"""Return per-sub data directory (creates if missing).
|
|
86
|
+
|
|
87
|
+
Each authenticated namespace gets its own scope under
|
|
88
|
+
``<CRG_DATA_DIR>/subs/<sub>/`` so graph state never leaks across users
|
|
89
|
+
sharing one deployment process.
|
|
90
|
+
"""
|
|
91
|
+
# sub must be a single path component to prevent traversal.
|
|
92
|
+
if (
|
|
93
|
+
not sub
|
|
94
|
+
or sub in (".", "..")
|
|
95
|
+
or "/" in sub
|
|
96
|
+
or "\\" in sub
|
|
97
|
+
or os.path.sep in sub
|
|
98
|
+
or (os.path.altsep and os.path.altsep in sub)
|
|
99
|
+
):
|
|
100
|
+
raise ValueError(f"Invalid subject (must be a single path component): {sub}")
|
|
101
|
+
|
|
102
|
+
base = Path(os.environ.get("CRG_DATA_DIR", str(Path.home() / ".crg")))
|
|
103
|
+
subs_base = (base / "subs").resolve()
|
|
104
|
+
|
|
105
|
+
# defense-in-depth: still verify the resolved path stays within subs_base
|
|
106
|
+
d = (subs_base / sub).resolve()
|
|
107
|
+
if not d.is_relative_to(subs_base) or d == subs_base:
|
|
108
|
+
raise ValueError(f"Invalid subject: {sub}")
|
|
109
|
+
|
|
110
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
111
|
+
return d
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def db_path_for_sub(sub: str) -> Path:
|
|
115
|
+
"""Return per-sub graph.db path for multi-user mode."""
|
|
116
|
+
return _sub_data_dir(sub) / "graph.db"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def set_current_sub(sub: str | None) -> None:
|
|
120
|
+
"""Bind the namespace subject for the current request (multi-user mode).
|
|
121
|
+
|
|
122
|
+
Normally the hull auth middleware's identity is consumed implicitly via
|
|
123
|
+
:func:`get_current_sub`; this explicit binding exists for tests and
|
|
124
|
+
host tooling that must scope work to one namespace outside a request.
|
|
125
|
+
Pass ``None`` to clear.
|
|
126
|
+
"""
|
|
127
|
+
_current_sub.set(sub)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def get_current_sub() -> str | None:
|
|
131
|
+
"""Return the namespace subject for the current request, or ``None``.
|
|
132
|
+
|
|
133
|
+
Resolution order:
|
|
134
|
+
|
|
135
|
+
1. Explicit :func:`set_current_sub` binding.
|
|
136
|
+
2. hull-core's request identity (``current_user()``) when the request
|
|
137
|
+
authenticated in ``multi`` mode — its namespace is the data root.
|
|
138
|
+
Worker-thread tool handlers inherit the contextvar via anyio's
|
|
139
|
+
context copy, same channel hull's own tools use.
|
|
140
|
+
|
|
141
|
+
``None`` means shared-namespace context (stdio, CLI, no-auth/token HTTP):
|
|
142
|
+
callers use the repo-local ``graph.db``.
|
|
143
|
+
"""
|
|
144
|
+
sub = _current_sub.get()
|
|
145
|
+
if sub is not None:
|
|
146
|
+
return sub
|
|
147
|
+
|
|
148
|
+
from hull_core.auth.context import current_user
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
ctx = current_user()
|
|
152
|
+
except Exception: # pragma: no cover - hull always present post de-host
|
|
153
|
+
return None
|
|
154
|
+
if ctx.mode == "multi" and ctx.namespace:
|
|
155
|
+
sub = ctx.namespace
|
|
156
|
+
# Reuse the path-safety validation so a hostile users.toml namespace
|
|
157
|
+
# cannot escape the subs/ root.
|
|
158
|
+
_sub_data_dir(sub)
|
|
159
|
+
return sub
|
|
160
|
+
return None
|