sourcecode 1.31.9__tar.gz → 1.31.10__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.
- {sourcecode-1.31.9 → sourcecode-1.31.10}/PKG-INFO +3 -3
- {sourcecode-1.31.9 → sourcecode-1.31.10}/README.md +2 -2
- {sourcecode-1.31.9 → sourcecode-1.31.10}/pyproject.toml +1 -1
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/classifier.py +1 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/dependency_analyzer.py +6 -1
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/java.py +29 -19
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/prepare_context.py +11 -9
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/repository_ir.py +181 -52
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/semantic_analyzer.py +26 -17
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.continue-here.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.gitignore +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.ruff.toml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-0911b79e.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-37df4554.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-624321f3.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-776b4676.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-9770fba7.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-c4e3c102.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-e8bc5fb4.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-e9801942.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-ee60e0cd.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/.sourcecode-cache/snapshot-0778d0a-fdd9d3f7.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/CHANGELOG.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/CONTRIBUTING.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/LICENSE +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/SECURITY.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/docs/privacy.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/docs/schema.md +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/raw +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/run_cli.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/cli.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/__init__.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/conftest.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/latin1_sample.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/latin1_sample_iso.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_broadleaf_fixes.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_bug_fixes_v1302.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_bug_fixes_v1312.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_bug_fixes_v1313.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_bug_fixes_v16.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_bug_fixes_v2.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_classifier.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_cli.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_python.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_encoding_regression.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_mcp_runner.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_mcp_serve.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_mcp_tools.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_output_ux.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_packaging.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_real_projects.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_redactor.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_repository_ir.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_scanner.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_schema.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_scoring_calibration.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_summarizer.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_surface_honesty.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_task_differentiation.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_telemetry.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_v131_improvements.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_v1_10_regressions.py +0 -0
- {sourcecode-1.31.9 → sourcecode-1.31.10}/tests/test_workspace_analyzer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.31.
|
|
3
|
+
Version: 1.31.10
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -225,7 +225,7 @@ Description-Content-Type: text/markdown
|
|
|
225
225
|
|
|
226
226
|
**Deterministic, behavior-aware codebase context for AI agents and PR review.**
|
|
227
227
|
|
|
228
|
-

|
|
229
229
|

|
|
230
230
|
|
|
231
231
|
---
|
|
@@ -261,7 +261,7 @@ pipx install sourcecode
|
|
|
261
261
|
|
|
262
262
|
```bash
|
|
263
263
|
sourcecode version
|
|
264
|
-
# sourcecode 1.31.
|
|
264
|
+
# sourcecode 1.31.10
|
|
265
265
|
```
|
|
266
266
|
|
|
267
267
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Deterministic, behavior-aware codebase context for AI agents and PR review.**
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|

|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -38,7 +38,7 @@ pipx install sourcecode
|
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
40
|
sourcecode version
|
|
41
|
-
# sourcecode 1.31.
|
|
41
|
+
# sourcecode 1.31.10
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
---
|
|
@@ -128,8 +128,13 @@ def _infer_role(name: str, ecosystem: str, scope: str) -> str:
|
|
|
128
128
|
return "runtime"
|
|
129
129
|
|
|
130
130
|
if ecosystem == "java":
|
|
131
|
+
# Scope is authoritative: provided and dev scopes are not runtime, regardless of
|
|
132
|
+
# artifact name. Checking artifact patterns first would mis-classify spring-boot-test
|
|
133
|
+
# (scope=test) as "runtime", inflating false-positive fan-in signals.
|
|
131
134
|
if scope == "provided":
|
|
132
135
|
return "provided"
|
|
136
|
+
if is_dev:
|
|
137
|
+
return "devtool"
|
|
133
138
|
artifact = n.split(":")[-1] if ":" in n else n
|
|
134
139
|
if any(x in artifact for x in ("spring-boot", "spring-security")):
|
|
135
140
|
return "runtime"
|
|
@@ -143,7 +148,7 @@ def _infer_role(name: str, ecosystem: str, scope: str) -> str:
|
|
|
143
148
|
return "parsing"
|
|
144
149
|
if any(x in artifact for x in ("jjwt", "nimbus-jose")):
|
|
145
150
|
return "runtime"
|
|
146
|
-
return "
|
|
151
|
+
return "runtime"
|
|
147
152
|
|
|
148
153
|
return "devtool" if is_dev else "runtime"
|
|
149
154
|
|
|
@@ -34,13 +34,16 @@ _HTTP_PATH_RE = re.compile(
|
|
|
34
34
|
_REQUEST_METHOD_VERB_RE = re.compile(
|
|
35
35
|
r'method\s*=\s*RequestMethod\.([A-Z]+)'
|
|
36
36
|
)
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
)
|
|
37
|
+
# Custom security annotation registry — extend here for project-specific annotations.
|
|
38
|
+
# Each entry: annotation_simple_name → compiled params regex.
|
|
39
|
+
# Groups: (1) resource string literal, (2) resource constant ref, (3) level integer.
|
|
40
|
+
_CUSTOM_SECURITY_ANNOTATIONS: dict[str, re.Pattern] = {
|
|
41
|
+
"M3FiltroSeguridad": re.compile(
|
|
42
|
+
r'@M3FiltroSeguridad\s*\(\s*'
|
|
43
|
+
r'(?:nombreRecurso\s*=\s*(?:"([^"]*)"|([\w.]+)))?'
|
|
44
|
+
r'(?:[^)]*nivelRequerido\s*=\s*(\d+))?'
|
|
45
|
+
),
|
|
46
|
+
}
|
|
44
47
|
|
|
45
48
|
# Security config detection
|
|
46
49
|
_WEB_SECURITY_CONFIGURER_RE = re.compile(r'WebSecurityConfigurerAdapter\b')
|
|
@@ -436,7 +439,7 @@ class JavaDetector(AbstractDetector):
|
|
|
436
439
|
))
|
|
437
440
|
if (not has_controller and not has_filter and not has_security
|
|
438
441
|
and "ControllerAdvice" not in content
|
|
439
|
-
and
|
|
442
|
+
and not any(ann in content for ann in _CUSTOM_SECURITY_ANNOTATIONS)
|
|
440
443
|
and not has_jax_rs and not has_cdi and not has_spi):
|
|
441
444
|
return []
|
|
442
445
|
|
|
@@ -449,11 +452,13 @@ class JavaDetector(AbstractDetector):
|
|
|
449
452
|
elif verb_match:
|
|
450
453
|
http_path = f"[{verb_match.group(1)}]"
|
|
451
454
|
security_evidence = None
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
455
|
+
for _ann_name, _ann_re in _CUSTOM_SECURITY_ANNOTATIONS.items():
|
|
456
|
+
_m = _ann_re.search(content)
|
|
457
|
+
if _m:
|
|
458
|
+
nombre = _m.group(1) or _m.group(2) or ""
|
|
459
|
+
nivel = _m.group(3) or ""
|
|
460
|
+
security_evidence = f"@{_ann_name}(nombreRecurso={nombre!r}, nivelRequerido={nivel})"
|
|
461
|
+
break
|
|
457
462
|
return [EntryPoint(
|
|
458
463
|
path=rel_path, stack="java", kind="rest_controller",
|
|
459
464
|
source="annotation", confidence="high",
|
|
@@ -474,11 +479,13 @@ class JavaDetector(AbstractDetector):
|
|
|
474
479
|
elif verb_match:
|
|
475
480
|
http_path = f"[{verb_match.group(1)}]"
|
|
476
481
|
security_evidence = None
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
+
for _ann_name, _ann_re in _CUSTOM_SECURITY_ANNOTATIONS.items():
|
|
483
|
+
_m = _ann_re.search(content)
|
|
484
|
+
if _m:
|
|
485
|
+
nombre = _m.group(1) or _m.group(2) or ""
|
|
486
|
+
nivel = _m.group(3) or ""
|
|
487
|
+
security_evidence = f"@{_ann_name}(nombreRecurso={nombre!r}, nivelRequerido={nivel})"
|
|
488
|
+
break
|
|
482
489
|
return [EntryPoint(
|
|
483
490
|
path=rel_path, stack="java", kind="mvc_controller",
|
|
484
491
|
source="annotation", confidence="medium",
|
|
@@ -514,7 +521,10 @@ class JavaDetector(AbstractDetector):
|
|
|
514
521
|
)]
|
|
515
522
|
|
|
516
523
|
# --- JAX-RS resource class ---
|
|
517
|
-
|
|
524
|
+
# Guard uses annotation PRESENCE ("@Path" in content), not _JAX_RS_PATH_RE, because
|
|
525
|
+
# the value-parsing regex fails for @Path(CONSTANT) and @Path(PREFIX + "/sub").
|
|
526
|
+
# _JAX_RS_PATH_RE is still used to extract the http_path display string when parseable.
|
|
527
|
+
if has_jax_rs and "@Path" in content and _JAX_RS_VERB_RE.search(content):
|
|
518
528
|
path_m = _JAX_RS_PATH_RE.search(content)
|
|
519
529
|
verb_m = _JAX_RS_VERB_RE.search(content)
|
|
520
530
|
http_path: str | None = None
|
|
@@ -2103,8 +2103,15 @@ class TaskContextBuilder:
|
|
|
2103
2103
|
_uncommitted = uncommitted_files or set()
|
|
2104
2104
|
_max_churn = max(_hotspots.values(), default=1)
|
|
2105
2105
|
|
|
2106
|
+
# Per-file note counts — feeds code_note_count into RankingEngine for all tasks.
|
|
2107
|
+
# RankingEngine is the sole ranking source; no ad-hoc annotation boost outside it.
|
|
2108
|
+
_note_counts: dict[str, int] = {}
|
|
2109
|
+
for _n in (code_notes or []):
|
|
2110
|
+
_np = getattr(_n, "path", "")
|
|
2111
|
+
if _np:
|
|
2112
|
+
_note_counts[_np] = _note_counts.get(_np, 0) + 1
|
|
2113
|
+
|
|
2106
2114
|
# Pre-compute fix-bug signals (used only when task_name == "fix-bug")
|
|
2107
|
-
_annotated_files: set[str] = set()
|
|
2108
2115
|
_dominant_stack = ""
|
|
2109
2116
|
_recently_changed_stacks: set[str] = set()
|
|
2110
2117
|
# Query-aware signals extracted from symptom (class names, exception types, tokens)
|
|
@@ -2113,10 +2120,6 @@ class TaskContextBuilder:
|
|
|
2113
2120
|
_symptom_tokens: set[str] = set() # all lowercase tokens
|
|
2114
2121
|
|
|
2115
2122
|
if task_name == "fix-bug":
|
|
2116
|
-
_bug_kinds = {"FIXME", "BUG", "HACK", "XXX"}
|
|
2117
|
-
for _n in (code_notes or []):
|
|
2118
|
-
if getattr(_n, "kind", "").upper() in _bug_kinds:
|
|
2119
|
-
_annotated_files.add(getattr(_n, "path", ""))
|
|
2120
2123
|
|
|
2121
2124
|
def _file_stack(p: str) -> str:
|
|
2122
2125
|
ext = Path(p).suffix.lower()
|
|
@@ -2167,13 +2170,15 @@ class TaskContextBuilder:
|
|
|
2167
2170
|
if is_test and task_name != "generate-tests":
|
|
2168
2171
|
continue
|
|
2169
2172
|
|
|
2170
|
-
# Structural + git signals from unified engine (task-weighted)
|
|
2173
|
+
# Structural + git signals from unified engine (task-weighted).
|
|
2174
|
+
# code_note_count routes annotation density through RankingEngine — single source.
|
|
2171
2175
|
fs = engine.score(
|
|
2172
2176
|
path,
|
|
2173
2177
|
is_entrypoint=(path in runtime_entry_set),
|
|
2174
2178
|
git_churn=_hotspots.get(path, 0),
|
|
2175
2179
|
max_churn=_max_churn,
|
|
2176
2180
|
is_changed=(path in _uncommitted),
|
|
2181
|
+
code_note_count=_note_counts.get(path, 0),
|
|
2177
2182
|
task=task_name,
|
|
2178
2183
|
)
|
|
2179
2184
|
|
|
@@ -2264,9 +2269,6 @@ class TaskContextBuilder:
|
|
|
2264
2269
|
if _recency > 0:
|
|
2265
2270
|
content_boost += _recency
|
|
2266
2271
|
_why_parts.append(f"recent commits (+{_recency:.2f})")
|
|
2267
|
-
if path in _annotated_files:
|
|
2268
|
-
content_boost += 0.20
|
|
2269
|
-
_why_parts.append("FIXME/BUG annotation (+0.20)")
|
|
2270
2272
|
_file_stk = _file_stack(path)
|
|
2271
2273
|
if _dominant_stack and _file_stk == _dominant_stack:
|
|
2272
2274
|
content_boost += 0.10
|
|
@@ -225,6 +225,14 @@ _SPRING_OTHER: frozenset[str] = frozenset({
|
|
|
225
225
|
|
|
226
226
|
_PUBLISH_EVENT_RE = re.compile(r'\.publishEvent\s*\(\s*new\s+(\w+)\s*[(\{]')
|
|
227
227
|
|
|
228
|
+
# Keycloak SPI event fire pattern: XxxEvent.fire(session, ...)
|
|
229
|
+
_FIRE_EVENT_RE = re.compile(r'\b(\w+Event)\.fire\s*\(')
|
|
230
|
+
|
|
231
|
+
# Edge types used for subsystem grouping — semantic hierarchy only, not imports
|
|
232
|
+
_SUBSYSTEM_STRUCTURAL_EDGES: frozenset[str] = frozenset({
|
|
233
|
+
"extends", "implements", "injects", "contained_in",
|
|
234
|
+
})
|
|
235
|
+
|
|
228
236
|
_HTTP_METHOD_MAP: dict[str, str] = {
|
|
229
237
|
# Spring MVC
|
|
230
238
|
"@GetMapping": "GET",
|
|
@@ -859,8 +867,8 @@ def _build_relations(
|
|
|
859
867
|
evidence={"type": "structural", "value": f"member of {enclosing}"},
|
|
860
868
|
))
|
|
861
869
|
|
|
862
|
-
#
|
|
863
|
-
#
|
|
870
|
+
# Event flow edges — listens_to_event and publishes_event.
|
|
871
|
+
# Spring: method with @EventListener → resolved event parameter type(s).
|
|
864
872
|
for sym in symbols:
|
|
865
873
|
if sym.type == "method" and "@EventListener" in sym.annotations:
|
|
866
874
|
for imp_fqn in sym.imports_used:
|
|
@@ -872,8 +880,9 @@ def _build_relations(
|
|
|
872
880
|
evidence={"type": "annotation", "value": "@EventListener"},
|
|
873
881
|
))
|
|
874
882
|
|
|
875
|
-
# publishes_event: class that calls publishEvent(new XxxEvent(...)) → event type FQN.
|
|
876
883
|
_class_syms = [s for s in symbols if s.type in ("class", "interface") and "#" not in s.symbol]
|
|
884
|
+
|
|
885
|
+
# Spring: class that calls publishEvent(new XxxEvent(...)) → event type FQN.
|
|
877
886
|
for m in _PUBLISH_EVENT_RE.finditer(source):
|
|
878
887
|
event_simple = m.group(1)
|
|
879
888
|
event_fqn = import_map.get(event_simple, event_simple)
|
|
@@ -886,6 +895,32 @@ def _build_relations(
|
|
|
886
895
|
evidence={"type": "method_call", "value": f"publishEvent(new {event_simple})"},
|
|
887
896
|
))
|
|
888
897
|
|
|
898
|
+
# Keycloak SPI: XxxEvent.fire(...) static dispatch → publishes_event.
|
|
899
|
+
for m in _FIRE_EVENT_RE.finditer(source):
|
|
900
|
+
event_simple = m.group(1)
|
|
901
|
+
event_fqn = import_map.get(event_simple, event_simple)
|
|
902
|
+
for cls_sym in _class_syms:
|
|
903
|
+
edges.append(RelationEdge(
|
|
904
|
+
from_symbol=cls_sym.symbol,
|
|
905
|
+
to_symbol=event_fqn,
|
|
906
|
+
type="publishes_event",
|
|
907
|
+
confidence="medium",
|
|
908
|
+
evidence={"type": "method_call", "value": f"{event_simple}.fire(...)"},
|
|
909
|
+
))
|
|
910
|
+
|
|
911
|
+
# Keycloak SPI: class implementing EventListenerProvider → listens_to_event.
|
|
912
|
+
_ELP_IFACE = "EventListenerProvider"
|
|
913
|
+
for sym in symbols:
|
|
914
|
+
if sym.type == "class" and _ELP_IFACE in (sym.signature or ""):
|
|
915
|
+
event_fqn = import_map.get("Event", "org.keycloak.events.Event")
|
|
916
|
+
edges.append(RelationEdge(
|
|
917
|
+
from_symbol=sym.symbol,
|
|
918
|
+
to_symbol=event_fqn,
|
|
919
|
+
type="listens_to_event",
|
|
920
|
+
confidence="high",
|
|
921
|
+
evidence={"type": "signature", "value": f"implements {_ELP_IFACE}"},
|
|
922
|
+
))
|
|
923
|
+
|
|
889
924
|
seen: set[tuple[str, str, str]] = set()
|
|
890
925
|
unique: list[RelationEdge] = []
|
|
891
926
|
for e in edges:
|
|
@@ -1248,49 +1283,72 @@ def _common_package_prefix(fqns: list[str]) -> str:
|
|
|
1248
1283
|
|
|
1249
1284
|
|
|
1250
1285
|
def _subsystem_label(package_prefix: str) -> str:
|
|
1251
|
-
"""Derive short human label
|
|
1286
|
+
"""Derive short human label enforcing minimum meaningful depth.
|
|
1287
|
+
|
|
1288
|
+
For org.keycloak.services → "keycloak.services" (not "services" alone).
|
|
1289
|
+
Avoids single-segment labels like "org" or "keycloak" that convey nothing.
|
|
1290
|
+
"""
|
|
1252
1291
|
parts = [p for p in package_prefix.split(".") if p]
|
|
1253
|
-
# Skip generic top-level segments
|
|
1254
1292
|
_SKIP = {"com", "org", "net", "io", "java", "javax"}
|
|
1255
1293
|
meaningful = [p for p in parts if p not in _SKIP]
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1294
|
+
if not meaningful:
|
|
1295
|
+
return parts[-1] if parts else package_prefix
|
|
1296
|
+
# Use last two meaningful segments for disambiguation:
|
|
1297
|
+
# org.keycloak.services → ["keycloak", "services"] → "keycloak.services"
|
|
1298
|
+
if len(meaningful) >= 2:
|
|
1299
|
+
return f"{meaningful[-2]}.{meaningful[-1]}"
|
|
1300
|
+
return meaningful[-1]
|
|
1301
|
+
|
|
1302
|
+
|
|
1303
|
+
def _canonical_subsystem_pkg(fqn: str) -> str:
|
|
1304
|
+
"""Canonical subsystem package for a FQN — minimum depth 3 for org/com/net/io packages.
|
|
1305
|
+
|
|
1306
|
+
org.keycloak.services.FooResource → org.keycloak.services
|
|
1307
|
+
org.keycloak.FooClass → org.keycloak
|
|
1308
|
+
com.example.util.Helper → com.example.util
|
|
1309
|
+
SomeTopLevelClass → SomeTopLevelClass
|
|
1310
|
+
|
|
1311
|
+
Never returns a bare TLD ("org", "com") — that collapses all classes into one subsystem.
|
|
1312
|
+
When only 1 lowercase segment exists before the class boundary, grabs one raw segment
|
|
1313
|
+
(even if uppercase) to force at least 2-segment grouping.
|
|
1314
|
+
"""
|
|
1315
|
+
_TOP_LEVEL = {"com", "org", "net", "io", "java", "javax"}
|
|
1316
|
+
parts: list[str] = []
|
|
1317
|
+
for segment in fqn.split("."):
|
|
1318
|
+
if "#" in segment or (segment and segment[0].isupper()):
|
|
1319
|
+
break
|
|
1320
|
+
parts.append(segment)
|
|
1321
|
+
if not parts:
|
|
1322
|
+
return fqn.rsplit(".", 1)[0] if "." in fqn else fqn
|
|
1323
|
+
if parts[0] in _TOP_LEVEL and len(parts) >= 3:
|
|
1324
|
+
return ".".join(parts[:3])
|
|
1325
|
+
# Prevent bare TLD collapse: "org" or "com" alone as subsystem key is meaningless
|
|
1326
|
+
# and groups ALL classes under that TLD into a single giant component.
|
|
1327
|
+
# When only the TLD was collected before hitting a class boundary, grab the next
|
|
1328
|
+
# raw FQN segment (may be uppercase) to produce a 2-segment grouping key.
|
|
1329
|
+
if parts[0] in _TOP_LEVEL and len(parts) == 1:
|
|
1330
|
+
raw = fqn.split(".")
|
|
1331
|
+
if len(raw) >= 2:
|
|
1332
|
+
return f"{raw[0]}.{raw[1].split('#')[0]}"
|
|
1333
|
+
return ".".join(parts)
|
|
1334
|
+
|
|
1335
|
+
|
|
1336
|
+
def _detect_subsystems(all_fqns: list[str], relations: list[RelationEdge]) -> list[dict]: # noqa: ARG001
|
|
1337
|
+
"""Group symbols by canonical subsystem package (minimum depth org.keycloak.<module>).
|
|
1338
|
+
|
|
1339
|
+
Uses package-prefix grouping instead of Union-Find on relation edges.
|
|
1340
|
+
Union-Find on imports produced one giant component ("org") for large monorepos.
|
|
1341
|
+
Package-prefix grouping at depth 3 yields meaningful module-level subsystems.
|
|
1263
1342
|
"""
|
|
1264
|
-
fqn_set = set(all_fqns)
|
|
1265
|
-
parent: dict[str, str] = {fqn: fqn for fqn in all_fqns}
|
|
1266
|
-
|
|
1267
|
-
def find(x: str) -> str:
|
|
1268
|
-
while parent[x] != x:
|
|
1269
|
-
parent[x] = parent[parent[x]]
|
|
1270
|
-
x = parent[x]
|
|
1271
|
-
return x
|
|
1272
|
-
|
|
1273
|
-
def union(x: str, y: str) -> None:
|
|
1274
|
-
rx, ry = find(x), find(y)
|
|
1275
|
-
if rx != ry:
|
|
1276
|
-
parent[rx] = ry
|
|
1277
|
-
|
|
1278
|
-
for edge in relations:
|
|
1279
|
-
f, t = edge.from_symbol, edge.to_symbol
|
|
1280
|
-
if f in fqn_set and t in fqn_set:
|
|
1281
|
-
union(f, t)
|
|
1282
|
-
|
|
1283
1343
|
components: dict[str, list[str]] = {}
|
|
1284
1344
|
for fqn in all_fqns:
|
|
1285
|
-
|
|
1286
|
-
components.setdefault(
|
|
1345
|
+
pkg = _canonical_subsystem_pkg(fqn)
|
|
1346
|
+
components.setdefault(pkg, []).append(fqn)
|
|
1287
1347
|
|
|
1288
1348
|
result: list[dict] = []
|
|
1289
|
-
for members in sorted(components.
|
|
1349
|
+
for pkg_prefix, members in sorted(components.items()):
|
|
1290
1350
|
members = sorted(members)
|
|
1291
|
-
pkg_prefix = _common_package_prefix(members)
|
|
1292
1351
|
label = _subsystem_label(pkg_prefix)
|
|
1293
|
-
# Summary: first 3 short class names + total count
|
|
1294
1352
|
short_names = [m.split(".")[-1].split("#")[0] for m in members[:3]]
|
|
1295
1353
|
summary = ", ".join(short_names)
|
|
1296
1354
|
if len(members) > 3:
|
|
@@ -1409,6 +1467,56 @@ def _bfs_impact_with_paths(
|
|
|
1409
1467
|
# Phase 5 — Assembly: single output contract
|
|
1410
1468
|
# ---------------------------------------------------------------------------
|
|
1411
1469
|
|
|
1470
|
+
def _compute_analysis_gaps(
|
|
1471
|
+
symbols: list[SymbolRecord],
|
|
1472
|
+
spring_summary: dict,
|
|
1473
|
+
route_surface: list[dict],
|
|
1474
|
+
relations: list[RelationEdge],
|
|
1475
|
+
) -> list[dict]:
|
|
1476
|
+
"""Compute structural analysis gaps — real system failures, not cosmetic issues."""
|
|
1477
|
+
gaps: list[dict] = []
|
|
1478
|
+
|
|
1479
|
+
if not symbols:
|
|
1480
|
+
gaps.append({
|
|
1481
|
+
"area": "symbol_extraction",
|
|
1482
|
+
"reason": "No Java symbols extracted — check path or file access",
|
|
1483
|
+
"impact": "high",
|
|
1484
|
+
})
|
|
1485
|
+
return gaps
|
|
1486
|
+
|
|
1487
|
+
controllers = spring_summary.get("controllers", [])
|
|
1488
|
+
if controllers and not route_surface:
|
|
1489
|
+
gaps.append({
|
|
1490
|
+
"area": "route_surface",
|
|
1491
|
+
"reason": (
|
|
1492
|
+
f"{len(controllers)} controller(s) detected but route_surface is empty — "
|
|
1493
|
+
"JAX-RS @Path or Spring @RequestMapping annotations may be missing"
|
|
1494
|
+
),
|
|
1495
|
+
"impact": "high",
|
|
1496
|
+
})
|
|
1497
|
+
|
|
1498
|
+
# Detect EventListenerProvider implementations via class signature, not class name.
|
|
1499
|
+
# A class named "CustomProcessor" implementing EventListenerProvider would be missed
|
|
1500
|
+
# by a class-name check but is correctly found via its implements clause in signature.
|
|
1501
|
+
_ELP_IFACE = "EventListenerProvider"
|
|
1502
|
+
elp_impls = [
|
|
1503
|
+
sym.symbol for sym in symbols
|
|
1504
|
+
if sym.type == "class" and _ELP_IFACE in (sym.signature or "")
|
|
1505
|
+
]
|
|
1506
|
+
event_edges = [e for e in relations if e.type in ("listens_to_event", "publishes_event")]
|
|
1507
|
+
if elp_impls and not event_edges:
|
|
1508
|
+
gaps.append({
|
|
1509
|
+
"area": "event_flow",
|
|
1510
|
+
"reason": (
|
|
1511
|
+
f"{len(elp_impls)} EventListenerProvider implementation(s) found but "
|
|
1512
|
+
"no event flow edges detected"
|
|
1513
|
+
),
|
|
1514
|
+
"impact": "medium",
|
|
1515
|
+
})
|
|
1516
|
+
|
|
1517
|
+
return gaps
|
|
1518
|
+
|
|
1519
|
+
|
|
1412
1520
|
def _edge_to_dict(edge: RelationEdge) -> dict:
|
|
1413
1521
|
return {
|
|
1414
1522
|
"from": edge.from_symbol,
|
|
@@ -1629,19 +1737,18 @@ def _assemble(
|
|
|
1629
1737
|
by_type.setdefault(e.type, []).append(e.from_symbol)
|
|
1630
1738
|
reverse_graph_out[target] = by_type
|
|
1631
1739
|
|
|
1632
|
-
# IC-005: aggregate event flow edges already built in _build_relations
|
|
1740
|
+
# IC-005: aggregate event flow edges already built in _build_relations.
|
|
1741
|
+
# Always emit spring_events (even when empty) so callers don't need key-presence checks.
|
|
1633
1742
|
_listen_edges = [e for e in sorted_rels if e.type == "listens_to_event"]
|
|
1634
1743
|
_publish_edges = [e for e in sorted_rels if e.type == "publishes_event"]
|
|
1635
|
-
_spring_events:
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
"flow_count": len(_listen_edges) + len(_publish_edges),
|
|
1642
|
-
}
|
|
1744
|
+
_spring_events: dict = {
|
|
1745
|
+
"listeners": sorted({e.from_symbol for e in _listen_edges}),
|
|
1746
|
+
"publishers": sorted({e.from_symbol for e in _publish_edges}),
|
|
1747
|
+
"event_types": sorted({e.to_symbol for e in _listen_edges + _publish_edges}),
|
|
1748
|
+
"flow_count": len(_listen_edges) + len(_publish_edges),
|
|
1749
|
+
}
|
|
1643
1750
|
|
|
1644
|
-
|
|
1751
|
+
_base = {
|
|
1645
1752
|
"schema_version": "final-v1",
|
|
1646
1753
|
"graph": {
|
|
1647
1754
|
"nodes": graph_nodes,
|
|
@@ -1662,11 +1769,19 @@ def _assemble(
|
|
|
1662
1769
|
},
|
|
1663
1770
|
"subsystems": subsystems,
|
|
1664
1771
|
"change_set": change_set_out,
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
_route_surface = _build_route_surface(sorted_syms, route_diffs, extends_map={
|
|
1775
|
+
e.from_symbol: e.to_symbol.split(".")[-1]
|
|
1776
|
+
for e in sorted_rels if e.type == "extends"
|
|
1777
|
+
})
|
|
1778
|
+
_analysis_gaps = _compute_analysis_gaps(sorted_syms, spring_summary, _route_surface, sorted_rels)
|
|
1779
|
+
|
|
1780
|
+
return {
|
|
1781
|
+
**_base,
|
|
1782
|
+
"route_surface": _route_surface,
|
|
1783
|
+
"spring_events": _spring_events,
|
|
1784
|
+
"analysis_gaps": _analysis_gaps,
|
|
1670
1785
|
"audit": {
|
|
1671
1786
|
"dropped_fields": dropped_fields,
|
|
1672
1787
|
},
|
|
@@ -1713,7 +1828,12 @@ def _build_route_surface(
|
|
|
1713
1828
|
# JAX-RS: class-level @Path is the resource prefix.
|
|
1714
1829
|
args = sym.annotation_values.get("@Path", "")
|
|
1715
1830
|
prefixes = _parse_route_paths(args) if args else [""]
|
|
1716
|
-
class_info[simple] = {
|
|
1831
|
+
class_info[simple] = {
|
|
1832
|
+
"fqn": sym.symbol,
|
|
1833
|
+
"prefixes": prefixes,
|
|
1834
|
+
"own_endpoints": [],
|
|
1835
|
+
"has_path_ann": "@Path" in sym.annotations or "@RequestMapping" in sym.annotations,
|
|
1836
|
+
}
|
|
1717
1837
|
|
|
1718
1838
|
routes: list[dict] = []
|
|
1719
1839
|
seen: set[tuple] = set()
|
|
@@ -1732,6 +1852,15 @@ def _build_route_surface(
|
|
|
1732
1852
|
# JAX-RS: HTTP verb annotations carry no path; path lives in @Path on the method.
|
|
1733
1853
|
if ann_name in _JAXRS_HTTP_ANNOTATIONS:
|
|
1734
1854
|
suffix = _parse_route_path(sym.annotation_values.get("@Path", ""))
|
|
1855
|
+
# Skip JAX-RS routes with no server-side path binding — client proxy interfaces
|
|
1856
|
+
# have HTTP verb annotations but neither a class-level @Path nor a method @Path.
|
|
1857
|
+
# Use has_path_ann (annotation presence) not just prefix value: @Path args may be
|
|
1858
|
+
# unparsed (multi-line, constant expression) yet the class IS a server resource.
|
|
1859
|
+
_cls_entry = class_info.get(cls_simple, {})
|
|
1860
|
+
cls_prefixes = _cls_entry.get("prefixes", [""])
|
|
1861
|
+
cls_has_path = _cls_entry.get("has_path_ann", False)
|
|
1862
|
+
if not suffix and not cls_has_path and all(not p for p in cls_prefixes):
|
|
1863
|
+
continue
|
|
1735
1864
|
else:
|
|
1736
1865
|
suffix = _parse_route_path(args)
|
|
1737
1866
|
method = _parse_route_http_method(ann_name, args) or "GET"
|
|
@@ -54,10 +54,18 @@ _MAPPER_IFACE_RE = re.compile(
|
|
|
54
54
|
_EXTENDS_RE = re.compile(
|
|
55
55
|
r'(?:class|interface)\s+([A-Z][A-Za-z0-9_]*)\s+extends\s+([A-Z][A-Za-z0-9_]*)'
|
|
56
56
|
)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
# Custom AOP annotation registry — extend here for project-specific security/AOP annotations.
|
|
58
|
+
# Each entry: (method_regex, impl_symbol_name).
|
|
59
|
+
# method_regex must capture the annotated method name in group 1.
|
|
60
|
+
_CUSTOM_AOP_ANNOTATIONS: list[tuple[re.Pattern, str]] = [
|
|
61
|
+
(
|
|
62
|
+
re.compile(
|
|
63
|
+
r'@M3FiltroSeguridad(?:\([^)]*\))?\s+(?:@[^\s]+\s+)*'
|
|
64
|
+
r'(?:public|private|protected)\s+\w[\w<>\[\]]*\s+([a-z][A-Za-z0-9_]*)\s*\('
|
|
65
|
+
),
|
|
66
|
+
"M3FiltroSeguridadImpl",
|
|
67
|
+
),
|
|
68
|
+
]
|
|
61
69
|
_LOMBOK_CLASS_RE = re.compile(
|
|
62
70
|
r'(@(?:Data|Slf4j|Builder|AllArgsConstructor|NoArgsConstructor)(?:\([^)]*\))?\s+)*'
|
|
63
71
|
r'(?:public\s+)?(?:class|interface)\s+([A-Z][A-Za-z0-9_]*)',
|
|
@@ -1061,19 +1069,20 @@ class SemanticAnalyzer:
|
|
|
1061
1069
|
method="heuristic",
|
|
1062
1070
|
))
|
|
1063
1071
|
|
|
1064
|
-
# P3-C:
|
|
1065
|
-
for
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1072
|
+
# P3-C: Custom AOP annotation proxy edges — driven by _CUSTOM_AOP_ANNOTATIONS registry
|
|
1073
|
+
for _aop_re, _aop_impl in _CUSTOM_AOP_ANNOTATIONS:
|
|
1074
|
+
for m in _aop_re.finditer(content):
|
|
1075
|
+
method_name = m.group(1)
|
|
1076
|
+
line = content[: m.start()].count("\n") + 1
|
|
1077
|
+
calls.append(CallRecord(
|
|
1078
|
+
caller_path=rel_path,
|
|
1079
|
+
caller_symbol=_aop_impl,
|
|
1080
|
+
callee_path=rel_path,
|
|
1081
|
+
callee_symbol=method_name,
|
|
1082
|
+
call_line=line,
|
|
1083
|
+
confidence="medium",
|
|
1084
|
+
method="heuristic",
|
|
1085
|
+
))
|
|
1077
1086
|
|
|
1078
1087
|
return symbols, calls
|
|
1079
1088
|
|
{sourcecode-1.31.9 → sourcecode-1.31.10}/.agents/skills/source-command-gsd-join-discord/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.31.9 → sourcecode-1.31.10}/.agents/skills/source-command-gsd-review-backlog/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.31.9 → sourcecode-1.31.10}/.agents/skills/source-command-gsd-workstreams/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|