sourcecode 1.31.7__tar.gz → 1.31.8__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.7 → sourcecode-1.31.8}/PKG-INFO +3 -3
- {sourcecode-1.31.7 → sourcecode-1.31.8}/README.md +2 -2
- {sourcecode-1.31.7 → sourcecode-1.31.8}/pyproject.toml +1 -1
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/architecture_analyzer.py +1 -1
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/cli.py +1 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/prepare_context.py +35 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/repository_ir.py +121 -16
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/runtime_classifier.py +79 -1
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/serializer.py +58 -0
- sourcecode-1.31.7/.sourcecode-cache/snapshot-265db75-03952dbd.json +0 -550
- sourcecode-1.31.7/.sourcecode-cache/snapshot-265db75-26a1ddd0.json +0 -550
- sourcecode-1.31.7/.sourcecode-cache/snapshot-265db75-37df4554.json +0 -266
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-0911b79e.json +0 -3825
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-37df4554.json +0 -266
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-624321f3.json +0 -12401
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-776b4676.json +0 -386
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-9770fba7.json +0 -373
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-c4e3c102.json +0 -266
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-e8bc5fb4.json +0 -122
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-e9801942.json +0 -219
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-ee60e0cd.json +0 -318
- sourcecode-1.31.7/.sourcecode-cache/snapshot-565fabf-fdd9d3f7.json +0 -552
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.continue-here.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.gitignore +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/.ruff.toml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/CHANGELOG.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/CONTRIBUTING.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/LICENSE +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/SECURITY.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/docs/privacy.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/docs/schema.md +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/raw +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/run_cli.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/__init__.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/conftest.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/latin1_sample.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/latin1_sample_iso.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_broadleaf_fixes.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_bug_fixes_v1302.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_bug_fixes_v1312.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_bug_fixes_v1313.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_bug_fixes_v16.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_bug_fixes_v2.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_classifier.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_cli.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_python.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_encoding_regression.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_mcp_runner.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_mcp_serve.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_mcp_tools.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_output_ux.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_packaging.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_real_projects.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_redactor.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_repository_ir.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_scanner.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_schema.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_scoring_calibration.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_summarizer.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_surface_honesty.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_task_differentiation.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_telemetry.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_v131_improvements.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/tests/test_v1_10_regressions.py +0 -0
- {sourcecode-1.31.7 → sourcecode-1.31.8}/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.8
|
|
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.8
|
|
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.8
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
---
|
|
@@ -330,7 +330,7 @@ class ArchitectureAnalyzer:
|
|
|
330
330
|
tentative = True
|
|
331
331
|
if not _hard_evidence:
|
|
332
332
|
limitations.append(
|
|
333
|
-
"Pattern
|
|
333
|
+
"Pattern inferred from directory structure; import graph not available — structural dependency direction unverified"
|
|
334
334
|
)
|
|
335
335
|
if not _hard_evidence:
|
|
336
336
|
matched_dirs = sorted({
|
|
@@ -836,6 +836,7 @@ def main(
|
|
|
836
836
|
code_notes = True
|
|
837
837
|
no_tree = True # agents never need the raw file tree
|
|
838
838
|
architecture = True # agents need full architectural signal (M4)
|
|
839
|
+
graph_modules = True # IC-003: import graph needed for architecture confidence
|
|
839
840
|
|
|
840
841
|
# ── GAP-9: Cache check — serve from .sourcecode-cache when git SHA unchanged ──
|
|
841
842
|
import hashlib as _hashlib
|
|
@@ -1212,6 +1212,41 @@ class TaskContextBuilder:
|
|
|
1212
1212
|
symptom=symptom if task_name == "fix-bug" else None,
|
|
1213
1213
|
)
|
|
1214
1214
|
|
|
1215
|
+
# ── IC-006: fix-bug suspected_areas — recompute from ranked files + bug notes ──
|
|
1216
|
+
# relevant_files is now ranked by RankingEngine (git churn, fan_in, centrality, notes).
|
|
1217
|
+
# suspected_areas should reflect that ranking, not raw comment count.
|
|
1218
|
+
if task_name == "fix-bug" and relevant_files:
|
|
1219
|
+
_bug_kinds = {"FIXME", "BUG", "HACK", "XXX"}
|
|
1220
|
+
_bug_counts: dict[str, int] = {}
|
|
1221
|
+
for _note in cn_notes_for_ranking:
|
|
1222
|
+
if _note.kind in _bug_kinds:
|
|
1223
|
+
_bug_counts[_note.path] = _bug_counts.get(_note.path, 0) + 1
|
|
1224
|
+
|
|
1225
|
+
# Primary: top-ranked RelevantFile objects (dataclass, use .path/.reason)
|
|
1226
|
+
_ranked_paths = [rf.path for rf in relevant_files[:30]]
|
|
1227
|
+
_primary: list[str] = []
|
|
1228
|
+
for rf in relevant_files[:30]:
|
|
1229
|
+
p = rf.path
|
|
1230
|
+
if not p:
|
|
1231
|
+
continue
|
|
1232
|
+
n = _bug_counts.get(p, 0)
|
|
1233
|
+
reason_str = str(rf.reason) if rf.reason else ""
|
|
1234
|
+
note_str = f" ({n} bug annotation{'s' if n > 1 else ''})" if n else ""
|
|
1235
|
+
_primary.append(f"{p}{note_str}" + (f" — {reason_str}" if reason_str else ""))
|
|
1236
|
+
if len(_primary) >= 5:
|
|
1237
|
+
break
|
|
1238
|
+
|
|
1239
|
+
# Secondary: remaining high-note files not already in primary
|
|
1240
|
+
_ranked_set = set(_ranked_paths[:len(_primary)])
|
|
1241
|
+
_secondary = [
|
|
1242
|
+
f"{p} ({n} annotation{'s' if n > 1 else ''})"
|
|
1243
|
+
for p, n in sorted(_bug_counts.items(), key=lambda x: -x[1])
|
|
1244
|
+
if p not in _ranked_set
|
|
1245
|
+
][:3]
|
|
1246
|
+
|
|
1247
|
+
if _primary or _secondary:
|
|
1248
|
+
suspected_areas = _primary + _secondary
|
|
1249
|
+
|
|
1215
1250
|
# ── 6b. review-pr: derive PR-specific impact sections from delta analysis ──
|
|
1216
1251
|
_pr_security_impact: dict = {}
|
|
1217
1252
|
_pr_transactional_impact: dict = {}
|
|
@@ -1537,6 +1537,18 @@ def _assemble(
|
|
|
1537
1537
|
by_type.setdefault(e.type, []).append(e.from_symbol)
|
|
1538
1538
|
reverse_graph_out[target] = by_type
|
|
1539
1539
|
|
|
1540
|
+
# IC-005: aggregate event flow edges already built in _build_relations
|
|
1541
|
+
_listen_edges = [e for e in sorted_rels if e.type == "listens_to_event"]
|
|
1542
|
+
_publish_edges = [e for e in sorted_rels if e.type == "publishes_event"]
|
|
1543
|
+
_spring_events: Optional[dict] = None
|
|
1544
|
+
if _listen_edges or _publish_edges:
|
|
1545
|
+
_spring_events = {
|
|
1546
|
+
"listeners": sorted({e.from_symbol for e in _listen_edges}),
|
|
1547
|
+
"publishers": sorted({e.from_symbol for e in _publish_edges}),
|
|
1548
|
+
"event_types": sorted({e.to_symbol for e in _listen_edges + _publish_edges}),
|
|
1549
|
+
"flow_count": len(_listen_edges) + len(_publish_edges),
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1540
1552
|
return {
|
|
1541
1553
|
"schema_version": "final-v1",
|
|
1542
1554
|
"graph": {
|
|
@@ -1558,7 +1570,11 @@ def _assemble(
|
|
|
1558
1570
|
},
|
|
1559
1571
|
"subsystems": subsystems,
|
|
1560
1572
|
"change_set": change_set_out,
|
|
1561
|
-
"route_surface": _build_route_surface(sorted_syms, route_diffs
|
|
1573
|
+
"route_surface": _build_route_surface(sorted_syms, route_diffs, extends_map={
|
|
1574
|
+
e.from_symbol: e.to_symbol.split(".")[-1]
|
|
1575
|
+
for e in sorted_rels if e.type == "extends"
|
|
1576
|
+
}),
|
|
1577
|
+
**({"spring_events": _spring_events} if _spring_events else {}),
|
|
1562
1578
|
"audit": {
|
|
1563
1579
|
"dropped_fields": dropped_fields,
|
|
1564
1580
|
},
|
|
@@ -1569,30 +1585,119 @@ def _assemble(
|
|
|
1569
1585
|
# Route surface helper (Fix 4)
|
|
1570
1586
|
# ---------------------------------------------------------------------------
|
|
1571
1587
|
|
|
1572
|
-
def _build_route_surface(
|
|
1573
|
-
|
|
1588
|
+
def _build_route_surface(
|
|
1589
|
+
symbols: list[SymbolRecord],
|
|
1590
|
+
route_diffs: Optional[list[dict]],
|
|
1591
|
+
extends_map: Optional[dict[str, str]] = None,
|
|
1592
|
+
) -> list[dict]:
|
|
1593
|
+
"""Return route surface with inheritance projection.
|
|
1594
|
+
|
|
1595
|
+
extends_map: child_fqn → parent_simple_name derived from RelationEdge extends edges.
|
|
1596
|
+
Projects inherited endpoints onto subclasses that have a class-level @RequestMapping
|
|
1597
|
+
prefix but zero own method-level endpoints (IC-001 fix).
|
|
1598
|
+
"""
|
|
1574
1599
|
if route_diffs:
|
|
1575
1600
|
return route_diffs
|
|
1601
|
+
|
|
1602
|
+
# Phase 1: build per-class metadata (prefix) and own endpoint list
|
|
1603
|
+
class_info: dict[str, dict] = {} # simple_name → {fqn, prefix, own_endpoints}
|
|
1604
|
+
for sym in symbols:
|
|
1605
|
+
if sym.type not in ("class", "interface"):
|
|
1606
|
+
continue
|
|
1607
|
+
simple = sym.symbol.split(".")[-1]
|
|
1608
|
+
prefix = ""
|
|
1609
|
+
if "@RequestMapping" in sym.annotations:
|
|
1610
|
+
args = sym.annotation_values.get("@RequestMapping", "")
|
|
1611
|
+
prefix = _parse_route_path(args)
|
|
1612
|
+
class_info[simple] = {"fqn": sym.symbol, "prefix": prefix, "own_endpoints": []}
|
|
1613
|
+
|
|
1576
1614
|
routes: list[dict] = []
|
|
1615
|
+
seen: set[tuple] = set()
|
|
1616
|
+
|
|
1617
|
+
# Phase 2: emit own endpoint symbols and record them per class
|
|
1577
1618
|
for sym in symbols:
|
|
1578
1619
|
if sym.symbol_kind != "endpoint":
|
|
1579
1620
|
continue
|
|
1580
1621
|
ann_name = next((a for a in sym.annotations if a in _ENDPOINT_ANNOTATIONS), None)
|
|
1581
1622
|
if not ann_name:
|
|
1582
1623
|
continue
|
|
1624
|
+
cls_fqn = _enclosing_class(sym.symbol)
|
|
1625
|
+
cls_simple = cls_fqn.split(".")[-1]
|
|
1583
1626
|
args = sym.annotation_values.get(ann_name, "")
|
|
1584
|
-
|
|
1585
|
-
method = _parse_route_http_method(ann_name, args)
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1627
|
+
suffix = _parse_route_path(args)
|
|
1628
|
+
method = _parse_route_http_method(ann_name, args) or "GET"
|
|
1629
|
+
|
|
1630
|
+
if cls_simple in class_info:
|
|
1631
|
+
class_info[cls_simple]["own_endpoints"].append(
|
|
1632
|
+
(method, suffix, sym.symbol, sym.stable_id)
|
|
1633
|
+
)
|
|
1634
|
+
|
|
1635
|
+
prefix = class_info.get(cls_simple, {}).get("prefix", "")
|
|
1636
|
+
full_path = (prefix + "/" + suffix).replace("//", "/").rstrip("/") or "/"
|
|
1637
|
+
if not full_path.startswith("/"):
|
|
1638
|
+
full_path = "/" + full_path
|
|
1639
|
+
|
|
1640
|
+
key = (sym.symbol, method, prefix)
|
|
1641
|
+
if key not in seen:
|
|
1642
|
+
seen.add(key)
|
|
1643
|
+
routes.append({
|
|
1644
|
+
"symbol": sym.symbol,
|
|
1645
|
+
"controller": cls_fqn,
|
|
1646
|
+
"declaring_class": cls_fqn,
|
|
1647
|
+
"effective_class": cls_fqn,
|
|
1648
|
+
"path": full_path,
|
|
1649
|
+
"method": method,
|
|
1650
|
+
"stable_id": sym.stable_id,
|
|
1651
|
+
"inheritance_depth": 0,
|
|
1652
|
+
})
|
|
1653
|
+
|
|
1654
|
+
# Phase 3: inheritance projection — subclasses with zero own endpoints
|
|
1655
|
+
# but with a class-level @RequestMapping prefix inherit parent methods.
|
|
1656
|
+
if extends_map:
|
|
1657
|
+
fqn_to_simple: dict[str, str] = {d["fqn"]: s for s, d in class_info.items()}
|
|
1658
|
+
simple_extends: dict[str, str] = {
|
|
1659
|
+
fqn_to_simple.get(child_fqn, child_fqn.split(".")[-1]): parent_simple
|
|
1660
|
+
for child_fqn, parent_simple in extends_map.items()
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
for cls_simple, data in class_info.items():
|
|
1664
|
+
if data["own_endpoints"]:
|
|
1665
|
+
continue
|
|
1666
|
+
if not data["prefix"]:
|
|
1667
|
+
continue
|
|
1668
|
+
|
|
1669
|
+
chain = simple_extends.get(cls_simple)
|
|
1670
|
+
visited: set[str] = {cls_simple}
|
|
1671
|
+
depth = 1
|
|
1672
|
+
while chain and chain not in visited:
|
|
1673
|
+
visited.add(chain)
|
|
1674
|
+
parent = class_info.get(chain)
|
|
1675
|
+
if not parent:
|
|
1676
|
+
break
|
|
1677
|
+
if parent["own_endpoints"]:
|
|
1678
|
+
for verb, suffix, declaring_sym, stable_id in parent["own_endpoints"]:
|
|
1679
|
+
prefix = data["prefix"]
|
|
1680
|
+
full_path = (prefix + "/" + suffix).replace("//", "/").rstrip("/") or "/"
|
|
1681
|
+
if not full_path.startswith("/"):
|
|
1682
|
+
full_path = "/" + full_path
|
|
1683
|
+
key = (cls_simple, declaring_sym, verb, prefix)
|
|
1684
|
+
if key not in seen:
|
|
1685
|
+
seen.add(key)
|
|
1686
|
+
routes.append({
|
|
1687
|
+
"symbol": declaring_sym,
|
|
1688
|
+
"controller": data["fqn"],
|
|
1689
|
+
"declaring_class": parent["fqn"],
|
|
1690
|
+
"effective_class": data["fqn"],
|
|
1691
|
+
"path": full_path,
|
|
1692
|
+
"method": verb,
|
|
1693
|
+
"stable_id": stable_id,
|
|
1694
|
+
"inheritance_depth": depth,
|
|
1695
|
+
})
|
|
1696
|
+
break
|
|
1697
|
+
chain = simple_extends.get(chain)
|
|
1698
|
+
depth += 1
|
|
1699
|
+
|
|
1700
|
+
return sorted(routes, key=lambda r: (r["effective_class"], r["path"]))
|
|
1596
1701
|
|
|
1597
1702
|
|
|
1598
1703
|
# ---------------------------------------------------------------------------
|
|
@@ -1803,7 +1908,7 @@ def apply_ir_size_limits(
|
|
|
1803
1908
|
# Convenience: find Java files in a repo
|
|
1804
1909
|
# ---------------------------------------------------------------------------
|
|
1805
1910
|
|
|
1806
|
-
def find_java_files(root: Path, *, max_files: int =
|
|
1911
|
+
def find_java_files(root: Path, *, max_files: int = 3000) -> list[str]:
|
|
1807
1912
|
"""Return relative paths to Java files under root, excluding test dirs and vendor."""
|
|
1808
1913
|
results: list[str] = []
|
|
1809
1914
|
for p in sorted(root.rglob("*.java")):
|
|
@@ -141,6 +141,11 @@ class RuntimeClassifier:
|
|
|
141
141
|
raw.append((ws_path, self._load_pkg_json(pkg_root)))
|
|
142
142
|
|
|
143
143
|
fan_in = self._compute_fan_in(raw)
|
|
144
|
+
# IC-004: merge Maven pom.xml cross-module fan_in when no JS deps detected
|
|
145
|
+
maven_fan_in = self._compute_maven_fan_in(root, workspace_paths)
|
|
146
|
+
for ws_path, count in maven_fan_in.items():
|
|
147
|
+
fan_in[ws_path] = fan_in.get(ws_path, 0) + count
|
|
148
|
+
|
|
144
149
|
results: list[MonorepoPackageInfo] = []
|
|
145
150
|
|
|
146
151
|
for ws_path, pkg_json in raw:
|
|
@@ -280,6 +285,9 @@ class RuntimeClassifier:
|
|
|
280
285
|
scores["infrastructure_layer"] = scores.get("infrastructure_layer", 0) + fan_boost
|
|
281
286
|
|
|
282
287
|
if not scores:
|
|
288
|
+
# IC-004: Java/Maven fallback — no JS signals but module may have a pom.xml
|
|
289
|
+
if not pkg_json:
|
|
290
|
+
return self._classify_maven_module(ws_path, name, fan_in)
|
|
283
291
|
return "unknown", signals, "low"
|
|
284
292
|
|
|
285
293
|
best_role = max(scores, key=lambda r: (scores[r], _ROLE_PRIORITY.get(r, 0)))
|
|
@@ -326,6 +334,76 @@ class RuntimeClassifier:
|
|
|
326
334
|
def _criticality(self, role: str, fan_in: int) -> str:
|
|
327
335
|
if role in {"runtime_core", "plugin_host"}:
|
|
328
336
|
return "high"
|
|
329
|
-
|
|
337
|
+
# IC-004: infrastructure_layer with high fan_in = shared foundation = high criticality
|
|
338
|
+
if role == "infrastructure_layer" and fan_in >= 3:
|
|
339
|
+
return "high"
|
|
340
|
+
if role in {"backend_runtime", "frontend_runtime", "composition_layer",
|
|
341
|
+
"infrastructure_layer"} or fan_in >= 3:
|
|
330
342
|
return "medium"
|
|
331
343
|
return "low"
|
|
344
|
+
|
|
345
|
+
def _compute_maven_fan_in(self, root: Path, workspace_paths: list[str]) -> dict[str, int]:
|
|
346
|
+
"""IC-004: Compute cross-module fan_in from all pom.xml files under each workspace.
|
|
347
|
+
|
|
348
|
+
Scans all pom.xml files (top-level and sub-module) within each workspace path.
|
|
349
|
+
Counts distinct modules that declare a dependency containing another module's leaf name.
|
|
350
|
+
Uses 1 hit per source module (not per pom file) to avoid inflation.
|
|
351
|
+
"""
|
|
352
|
+
fan_in: dict[str, int] = {}
|
|
353
|
+
leaf_to_path: dict[str, str] = {ws.split("/")[-1]: ws for ws in workspace_paths}
|
|
354
|
+
|
|
355
|
+
for ws_path in workspace_paths:
|
|
356
|
+
ws_dir = root / ws_path
|
|
357
|
+
if not ws_dir.is_dir():
|
|
358
|
+
continue
|
|
359
|
+
deps_found: set[str] = set()
|
|
360
|
+
for pom in ws_dir.rglob("pom.xml"):
|
|
361
|
+
if "target/" in str(pom):
|
|
362
|
+
continue
|
|
363
|
+
try:
|
|
364
|
+
content = pom.read_text(encoding="utf-8", errors="replace")
|
|
365
|
+
except OSError:
|
|
366
|
+
continue
|
|
367
|
+
for dep_leaf, target_path in leaf_to_path.items():
|
|
368
|
+
if target_path != ws_path and dep_leaf in content:
|
|
369
|
+
deps_found.add(target_path)
|
|
370
|
+
for target_path in deps_found:
|
|
371
|
+
fan_in[target_path] = fan_in.get(target_path, 0) + 1
|
|
372
|
+
|
|
373
|
+
return fan_in
|
|
374
|
+
|
|
375
|
+
def _classify_maven_module(
|
|
376
|
+
self, ws_path: str, name: str, fan_in: int
|
|
377
|
+
) -> tuple[str, list[str], str]:
|
|
378
|
+
"""IC-004: Classify a Java/Maven module by path conventions and fan_in.
|
|
379
|
+
|
|
380
|
+
Called when no JS signals exist (no package.json). Uses path name patterns
|
|
381
|
+
and pom fan_in (cross-module dependency count) to determine role/criticality.
|
|
382
|
+
"""
|
|
383
|
+
signals: list[str] = ["maven:module"]
|
|
384
|
+
leaf = ws_path.lower().rstrip("/").split("/")[-1]
|
|
385
|
+
|
|
386
|
+
if re.search(r"\b(common|shared|util|utils|lib|base|foundation)\b", leaf):
|
|
387
|
+
signals.append("maven:shared_library")
|
|
388
|
+
return "infrastructure_layer", signals, "high" if fan_in >= 3 else "medium"
|
|
389
|
+
|
|
390
|
+
if re.search(r"\b(integration|it|test|tests|e2e)\b", leaf):
|
|
391
|
+
signals.append("maven:test_module")
|
|
392
|
+
return "test_layer", signals, "low"
|
|
393
|
+
|
|
394
|
+
if re.search(r"\b(admin|web|api|rest|controller|ui)\b", leaf):
|
|
395
|
+
signals.append("maven:web_module")
|
|
396
|
+
return "backend_runtime", signals, "medium"
|
|
397
|
+
|
|
398
|
+
if re.search(r"\b(core|framework|domain|service|profile)\b", leaf):
|
|
399
|
+
signals.append("maven:core_module")
|
|
400
|
+
return "backend_runtime", signals, "high" if fan_in >= 2 else "medium"
|
|
401
|
+
|
|
402
|
+
if fan_in >= 3:
|
|
403
|
+
signals.append(f"maven:high_fan_in({fan_in})")
|
|
404
|
+
return "infrastructure_layer", signals, "high"
|
|
405
|
+
if fan_in >= 1:
|
|
406
|
+
signals.append(f"maven:fan_in({fan_in})")
|
|
407
|
+
return "infrastructure_layer", signals, "medium"
|
|
408
|
+
|
|
409
|
+
return "unknown", signals, "low"
|
|
@@ -379,6 +379,59 @@ def _spring_boot_version(sm: "SourceMap") -> "Optional[str]":
|
|
|
379
379
|
return None
|
|
380
380
|
|
|
381
381
|
|
|
382
|
+
def _spring_event_signal(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
383
|
+
"""IC-005: Surface @EventListener and publishEvent from Java source files.
|
|
384
|
+
|
|
385
|
+
Scans sm.file_paths for Java files containing Spring event annotations.
|
|
386
|
+
Only runs on Java/Spring projects. Lightweight — path heuristics first,
|
|
387
|
+
then targeted content scan on candidate files only.
|
|
388
|
+
"""
|
|
389
|
+
import re as _re
|
|
390
|
+
java_paths = [p for p in sm.file_paths if p.endswith(".java") and "target/" not in p]
|
|
391
|
+
if not java_paths:
|
|
392
|
+
return None
|
|
393
|
+
_frameworks = [f.name for s in (sm.stacks or []) for f in s.frameworks]
|
|
394
|
+
if not any("Spring" in fw for fw in _frameworks):
|
|
395
|
+
return None
|
|
396
|
+
|
|
397
|
+
analyzed_path = getattr(sm.metadata, "analyzed_path", None) if sm.metadata else None
|
|
398
|
+
root = Path(analyzed_path) if analyzed_path else None
|
|
399
|
+
|
|
400
|
+
listeners: list[str] = []
|
|
401
|
+
publishers: list[str] = []
|
|
402
|
+
event_types: set[str] = set()
|
|
403
|
+
_publish_re = _re.compile(r"\.publishEvent\s*\(\s*new\s+(\w+)")
|
|
404
|
+
|
|
405
|
+
for rel_path in java_paths:
|
|
406
|
+
if root is None:
|
|
407
|
+
break
|
|
408
|
+
try:
|
|
409
|
+
content = (root / rel_path).read_text(encoding="utf-8", errors="replace")
|
|
410
|
+
except OSError:
|
|
411
|
+
continue
|
|
412
|
+
if "@EventListener" in content:
|
|
413
|
+
cls_m = _re.search(r"class\s+(\w+)", content)
|
|
414
|
+
cls_name = cls_m.group(1) if cls_m else Path(rel_path).stem
|
|
415
|
+
if cls_name not in listeners:
|
|
416
|
+
listeners.append(cls_name)
|
|
417
|
+
for m in _publish_re.finditer(content):
|
|
418
|
+
event_types.add(m.group(1))
|
|
419
|
+
cls_m = _re.search(r"class\s+(\w+)", content)
|
|
420
|
+
cls_name = cls_m.group(1) if cls_m else Path(rel_path).stem
|
|
421
|
+
if cls_name not in publishers:
|
|
422
|
+
publishers.append(cls_name)
|
|
423
|
+
|
|
424
|
+
if not listeners and not publishers:
|
|
425
|
+
return None
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
"listeners": sorted(set(listeners))[:10],
|
|
429
|
+
"publishers": sorted(set(publishers))[:10],
|
|
430
|
+
"event_types": sorted(event_types)[:10],
|
|
431
|
+
"flow_count": len(listeners) + len(publishers),
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
|
|
382
435
|
def _spring_profiles_context(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
383
436
|
"""Build structured spring_profiles block: detected names + per-profile file variants."""
|
|
384
437
|
# Gather profile names from env_summary (populated by env_analyzer scanning
|
|
@@ -1949,6 +2002,11 @@ def agent_view(sm: SourceMap, *, full: bool = False) -> dict[str, Any]:
|
|
|
1949
2002
|
if _txn:
|
|
1950
2003
|
signals["transactional_boundaries"] = _txn
|
|
1951
2004
|
|
|
2005
|
+
# IC-005: Spring event flows (@EventListener / publishEvent)
|
|
2006
|
+
_evf = _spring_event_signal(sm)
|
|
2007
|
+
if _evf:
|
|
2008
|
+
signals["event_flows"] = _evf
|
|
2009
|
+
|
|
1952
2010
|
if signals:
|
|
1953
2011
|
result["signals"] = signals
|
|
1954
2012
|
|