sourcecode 1.10.0__tar.gz → 1.12.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.
- {sourcecode-1.10.0 → sourcecode-1.12.0}/PKG-INFO +38 -66
- sourcecode-1.12.0/README.md +114 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/pyproject.toml +1 -1
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/cli.py +28 -7
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/java.py +99 -3
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/project.py +3 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/prepare_context.py +19 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/schema.py +1 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/serializer.py +342 -36
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/summarizer.py +7 -1
- sourcecode-1.12.0/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +17 -0
- sourcecode-1.12.0/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +16 -0
- sourcecode-1.12.0/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +8 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_cli.py +1 -1
- sourcecode-1.12.0/tests/test_surface_honesty.py +339 -0
- sourcecode-1.12.0/tests/test_v1_10_regressions.py +560 -0
- sourcecode-1.10.0/README.md +0 -142
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.continue-here.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.gitignore +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/.ruff.toml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/CONTRIBUTING.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/LICENSE +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/SECURITY.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/docs/privacy.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/docs/schema.md +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/raw +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/run_cli.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/__init__.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/conftest.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_bug_fixes_v16.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_classifier.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_python.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_packaging.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_real_projects.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_redactor.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_scanner.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_schema.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_summarizer.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_telemetry.py +0 -0
- {sourcecode-1.10.0 → sourcecode-1.12.0}/tests/test_workspace_analyzer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.12.0
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -254,48 +254,45 @@ sourcecode version
|
|
|
254
254
|
|
|
255
255
|
## Quickstart
|
|
256
256
|
|
|
257
|
-
The
|
|
257
|
+
The primary command — a high-signal, low-noise summary for Java/Spring codebases:
|
|
258
258
|
|
|
259
259
|
```bash
|
|
260
|
-
sourcecode --
|
|
260
|
+
sourcecode --compact
|
|
261
|
+
# ~600-800 tokens: stack, entry points, dependencies, risk flags, confidence.
|
|
262
|
+
|
|
263
|
+
sourcecode --compact --git-context
|
|
264
|
+
# Adds git hotspots and uncommitted file count.
|
|
265
|
+
|
|
266
|
+
sourcecode --compact --copy
|
|
267
|
+
# Copies the result to clipboard.
|
|
261
268
|
```
|
|
262
269
|
|
|
263
|
-
|
|
270
|
+
Example output for a Spring Boot project:
|
|
264
271
|
|
|
265
272
|
```json
|
|
266
273
|
{
|
|
267
|
-
"
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
"
|
|
271
|
-
"
|
|
274
|
+
"project_type": "api",
|
|
275
|
+
"stacks": [{ "stack": "java", "frameworks": ["Spring Boot", "MyBatis"] }],
|
|
276
|
+
"entry_points": {
|
|
277
|
+
"bootstrap": ["src/main/java/io/spring/RealWorldApplication.java"],
|
|
278
|
+
"security": ["src/main/java/io/spring/api/security/WebSecurityConfig.java"],
|
|
279
|
+
"controllers": { "count": 8, "sample": [...] }
|
|
272
280
|
},
|
|
273
|
-
"
|
|
274
|
-
{
|
|
275
|
-
"
|
|
276
|
-
"stack": "java",
|
|
277
|
-
"kind": "application",
|
|
278
|
-
"confidence": "high"
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
"path": "atlas-client/src/main.ts",
|
|
282
|
-
"stack": "nodejs",
|
|
283
|
-
"kind": "entrypoint",
|
|
284
|
-
"confidence": "high"
|
|
285
|
-
}
|
|
281
|
+
"key_dependencies": [
|
|
282
|
+
{ "name": "org.mybatis.spring.boot:mybatis-spring-boot-starter",
|
|
283
|
+
"version": "2.2.2", "risk_flags": ["spring-boot-2.x-eol"] }
|
|
286
284
|
],
|
|
287
|
-
"
|
|
288
|
-
"
|
|
289
|
-
"
|
|
290
|
-
"
|
|
285
|
+
"language_version": "11",
|
|
286
|
+
"deployment": { "spring_boot_version": "2.6.3" },
|
|
287
|
+
"mybatis": { "mapper_interfaces": 4, "xml_files": 4 },
|
|
288
|
+
"confidence_summary": { "overall": "high" }
|
|
291
289
|
}
|
|
292
290
|
```
|
|
293
291
|
|
|
294
|
-
For
|
|
292
|
+
For full structured output with per-file contracts and signals, use `--agent`:
|
|
295
293
|
|
|
296
294
|
```bash
|
|
297
|
-
sourcecode --
|
|
298
|
-
# Copies the summary to the clipboard. Ready to paste.
|
|
295
|
+
sourcecode --agent
|
|
299
296
|
```
|
|
300
297
|
|
|
301
298
|
---
|
|
@@ -304,41 +301,18 @@ sourcecode --compact --copy
|
|
|
304
301
|
|
|
305
302
|
### Global options
|
|
306
303
|
|
|
307
|
-
| Flag | Alias | Type | Default | Description |
|
|
308
|
-
|
|
309
|
-
| `--
|
|
310
|
-
| `--
|
|
311
|
-
| `--
|
|
312
|
-
| `--
|
|
313
|
-
| `--
|
|
314
|
-
| `--
|
|
315
|
-
| `--
|
|
316
|
-
| `--
|
|
317
|
-
| `--
|
|
318
|
-
| `--
|
|
319
|
-
| `--copy` | `-c` | flag | off | Copies output to the clipboard after successful execution. | ✅ CORE |
|
|
320
|
-
| `--depth` | | `INT [1–20]` | `4` | Maximum file tree traversal depth. Java/Maven requires ≥8. | ✅ CORE |
|
|
321
|
-
| `--mode` | | `contract\|standard\|raw` | `contract` | `contract`: minimal contracts per file. `standard`: full detail. `raw`: project level only. | ✅ CORE |
|
|
322
|
-
| `--tree` | | flag | off | Includes full `file_tree` and `file_paths` in the output. Increases size significantly. | ✅ CORE |
|
|
323
|
-
| `--changed-only` | | flag | off | Contract mode: only files modified in git (staged, unstaged, untracked). | ✅ CORE |
|
|
324
|
-
| `--rank-by` | | `relevance\|centrality\|git-churn` | `relevance` | File ranking strategy in contract mode. | ✅ CORE |
|
|
325
|
-
| `--semantics` | | flag | off | Cross-file symbol resolution, call graph with confidence levels, fan-in/fan-out hotspots. Slower. | 🧪 EXP |
|
|
326
|
-
| `--architecture` | | flag | off | Architectural layer inference (MVC/hexagonal/bounded contexts). Low confidence without `--semantics`. | 🧪 EXP |
|
|
327
|
-
| `--graph-modules` | | flag | off | Structural module graph: nodes (files/symbols) and edges (imports, calls, contains). | 🧪 EXP |
|
|
328
|
-
| `--graph-detail` | | `high\|medium\|full` | `high` | Module graph detail level. | 🧪 EXP |
|
|
329
|
-
| `--max-nodes` | | `INT [≥1]` | — | Maximum nodes in `--graph-modules`. Prevents huge graphs in large repos. | 🧪 EXP |
|
|
330
|
-
| `--graph-edges` | | `TEXT` | all | Edge types for `--graph-modules`, comma-separated: `imports,calls,contains`. | 🧪 EXP |
|
|
331
|
-
| `--docs` | | flag | off | Extracts docstrings, function signatures, and module comments. | 🧪 EXP |
|
|
332
|
-
| `--docs-depth` | | `module\|symbols\|full` | `symbols` | Docs extraction depth. `full` includes private symbols. | 🧪 EXP |
|
|
333
|
-
| `--symbol` | | `TEXT` | — | Contract mode: localized context for a specific symbol. Python, TS, JS only. **Does not support Java.** | 🧪 EXP |
|
|
334
|
-
| `--max-importers` | | `INT [1–10000]` | `50` | Limit on importer files returned by `--symbol`. | 🧪 EXP |
|
|
335
|
-
| `--full-metrics` | | flag | off | Per-file technical metrics: LOC, cyclomatic complexity, coverage. Aimed at CI, not at agents. | 🧪 EXP |
|
|
336
|
-
| `--emit-graph` | | flag | off | Contract mode: includes a compact dependency graph (nodes + edges) in the output. | 🚧 WIP |
|
|
337
|
-
| `--entrypoints-only` | | flag | off | Contract mode: only files with exports or entry points. Note: includes *all* files with exports. | 🚧 WIP |
|
|
338
|
-
| `--max-symbols` | | `INT [≥1]` | — | Limits total exported symbols in contract mode. Discards lower-ranked files. | 🚧 WIP |
|
|
339
|
-
| `--no-redact` | | flag | off | Disables automatic secret redaction. Output may contain sensitive values. | 🚧 WIP |
|
|
340
|
-
| `--trace-pipeline` | | flag | off | Diagnostic mode: includes a trace of each candidate and filtering decision. Debugging only. | 🚧 WIP |
|
|
341
|
-
| `--version` | `-v` | flag | — | Shows version and exits. | ✅ CORE |
|
|
304
|
+
| Flag | Alias | Type | Default | Description |
|
|
305
|
+
|------|-------|------|---------|-------------|
|
|
306
|
+
| `--compact` | | flag | off | **Recommended.** ~600-800 token summary: stack, entry points, deps, risk flags, confidence. |
|
|
307
|
+
| `--git-context` | `-g` | flag | off | Adds git hotspots (top changed files), branch, uncommitted file count. Use with `--compact`. |
|
|
308
|
+
| `--agent` | | flag | off | Full structured JSON for AI agents. Auto-enables dependency, env-var, and code-notes analysis. |
|
|
309
|
+
| `--changed-only` | | flag | off | Limit output to git-modified files (staged, unstaged, untracked). |
|
|
310
|
+
| `--depth` | | `INT [1–20]` | `4` | File tree traversal depth. Java projects auto-adjust to 12. |
|
|
311
|
+
| `--format` | `-f` | `json\|yaml` | `json` | Output format. JSON preferred in pipelines. |
|
|
312
|
+
| `--output` | `-o` | `PATH` | stdout | Write output to a file instead of stdout. |
|
|
313
|
+
| `--copy` | `-c` | flag | off | Copy output to clipboard after a successful run. |
|
|
314
|
+
| `--no-redact` | | flag | off | Disable automatic secret redaction. Output may contain sensitive values. |
|
|
315
|
+
| `--version` | `-v` | flag | — | Show version and exit. |
|
|
342
316
|
|
|
343
317
|
---
|
|
344
318
|
|
|
@@ -357,5 +331,3 @@ Generates task-specific context for AI agents.
|
|
|
357
331
|
| `refactor` | Structural problems, improvement opportunities | 🧪 EXP |
|
|
358
332
|
| `generate-tests` | Files without tests, coverage gap analysis | 🧪 EXP |
|
|
359
333
|
| `review-pr` | Changed files + architectural impact | 🧪 EXP |
|
|
360
|
-
|
|
361
|
-
...
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# sourcecode
|
|
2
|
+
|
|
3
|
+
**Deterministic codebase context for AI coding agents.**
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What is it?
|
|
12
|
+
|
|
13
|
+
`sourcecode` analyzes a repository and produces a structured context map (JSON or YAML) designed to be consumed by AI agents or language models. It solves the "stuff the whole repo into the prompt" problem by instead producing a deterministic extract: entry points, dependencies, stacks, inline annotations, environment variables, and git activity. It is an MVP tool under active evolution — the semantic analysis and module graph features work but have known limitations that are explicitly documented below.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
**Prerequisites:** Python 3.10+
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install sourcecode
|
|
23
|
+
# or with pipx for isolation:
|
|
24
|
+
pipx install sourcecode
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Verify installation:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
sourcecode version
|
|
31
|
+
# sourcecode 1.0.0
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Quickstart
|
|
37
|
+
|
|
38
|
+
The primary command — a high-signal, low-noise summary for Java/Spring codebases:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
sourcecode --compact
|
|
42
|
+
# ~600-800 tokens: stack, entry points, dependencies, risk flags, confidence.
|
|
43
|
+
|
|
44
|
+
sourcecode --compact --git-context
|
|
45
|
+
# Adds git hotspots and uncommitted file count.
|
|
46
|
+
|
|
47
|
+
sourcecode --compact --copy
|
|
48
|
+
# Copies the result to clipboard.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Example output for a Spring Boot project:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"project_type": "api",
|
|
56
|
+
"stacks": [{ "stack": "java", "frameworks": ["Spring Boot", "MyBatis"] }],
|
|
57
|
+
"entry_points": {
|
|
58
|
+
"bootstrap": ["src/main/java/io/spring/RealWorldApplication.java"],
|
|
59
|
+
"security": ["src/main/java/io/spring/api/security/WebSecurityConfig.java"],
|
|
60
|
+
"controllers": { "count": 8, "sample": [...] }
|
|
61
|
+
},
|
|
62
|
+
"key_dependencies": [
|
|
63
|
+
{ "name": "org.mybatis.spring.boot:mybatis-spring-boot-starter",
|
|
64
|
+
"version": "2.2.2", "risk_flags": ["spring-boot-2.x-eol"] }
|
|
65
|
+
],
|
|
66
|
+
"language_version": "11",
|
|
67
|
+
"deployment": { "spring_boot_version": "2.6.3" },
|
|
68
|
+
"mybatis": { "mapper_interfaces": 4, "xml_files": 4 },
|
|
69
|
+
"confidence_summary": { "overall": "high" }
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For full structured output with per-file contracts and signals, use `--agent`:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
sourcecode --agent
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Flags reference
|
|
82
|
+
|
|
83
|
+
### Global options
|
|
84
|
+
|
|
85
|
+
| Flag | Alias | Type | Default | Description |
|
|
86
|
+
|------|-------|------|---------|-------------|
|
|
87
|
+
| `--compact` | | flag | off | **Recommended.** ~600-800 token summary: stack, entry points, deps, risk flags, confidence. |
|
|
88
|
+
| `--git-context` | `-g` | flag | off | Adds git hotspots (top changed files), branch, uncommitted file count. Use with `--compact`. |
|
|
89
|
+
| `--agent` | | flag | off | Full structured JSON for AI agents. Auto-enables dependency, env-var, and code-notes analysis. |
|
|
90
|
+
| `--changed-only` | | flag | off | Limit output to git-modified files (staged, unstaged, untracked). |
|
|
91
|
+
| `--depth` | | `INT [1–20]` | `4` | File tree traversal depth. Java projects auto-adjust to 12. |
|
|
92
|
+
| `--format` | `-f` | `json\|yaml` | `json` | Output format. JSON preferred in pipelines. |
|
|
93
|
+
| `--output` | `-o` | `PATH` | stdout | Write output to a file instead of stdout. |
|
|
94
|
+
| `--copy` | `-c` | flag | off | Copy output to clipboard after a successful run. |
|
|
95
|
+
| `--no-redact` | | flag | off | Disable automatic secret redaction. Output may contain sensitive values. |
|
|
96
|
+
| `--version` | `-v` | flag | — | Show version and exit. |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Subcommands
|
|
101
|
+
|
|
102
|
+
### `prepare-context TASK [PATH]`
|
|
103
|
+
|
|
104
|
+
Generates task-specific context for AI agents.
|
|
105
|
+
|
|
106
|
+
| Task | Description | Status |
|
|
107
|
+
|------|-------------|--------|
|
|
108
|
+
| `explain` | Architecture, entry points, key dependencies | ✅ CORE |
|
|
109
|
+
| `fix-bug` | Files prioritized by risk, inline annotations | ✅ CORE |
|
|
110
|
+
| `onboard` | Full context for new agents or developers | ✅ CORE |
|
|
111
|
+
| `delta` | Incremental context: only files changed in git | ✅ CORE |
|
|
112
|
+
| `refactor` | Structural problems, improvement opportunities | 🧪 EXP |
|
|
113
|
+
| `generate-tests` | Files without tests, coverage gap analysis | 🧪 EXP |
|
|
114
|
+
| `review-pr` | Changed files + architectural impact | 🧪 EXP |
|
|
@@ -141,10 +141,14 @@ def _check_pipeline_coherence(sm: "SourceMap") -> list[str]: # type: ignore[nam
|
|
|
141
141
|
_HELP = """\
|
|
142
142
|
Compressed AI-ready context for Java/Spring enterprise codebases.
|
|
143
143
|
|
|
144
|
+
[bold]Primary usage:[/bold]
|
|
145
|
+
sourcecode --compact high-signal summary (~600-800 tokens)
|
|
146
|
+
sourcecode --compact --git-context include git hotspots and uncommitted files
|
|
147
|
+
|
|
144
148
|
[bold]Examples:[/bold]
|
|
145
149
|
sourcecode saint-server --compact
|
|
150
|
+
sourcecode . --compact --git-context --copy
|
|
146
151
|
sourcecode . --changed-only --git-context
|
|
147
|
-
sourcecode saint-server --symbol SeguridadRestController
|
|
148
152
|
sourcecode prepare-context onboard saint-server
|
|
149
153
|
sourcecode prepare-context delta . --since main
|
|
150
154
|
|
|
@@ -565,7 +569,8 @@ def main(
|
|
|
565
569
|
symbol: Optional[str] = typer.Option(
|
|
566
570
|
None,
|
|
567
571
|
"--symbol",
|
|
568
|
-
|
|
572
|
+
hidden=True,
|
|
573
|
+
help="Extract context for a specific symbol (Python/TS/JS only — not supported for Java).",
|
|
569
574
|
),
|
|
570
575
|
max_importers: int = typer.Option(
|
|
571
576
|
50,
|
|
@@ -586,10 +591,10 @@ def main(
|
|
|
586
591
|
|
|
587
592
|
\b
|
|
588
593
|
Examples:
|
|
589
|
-
sourcecode
|
|
590
|
-
sourcecode
|
|
591
|
-
sourcecode --
|
|
592
|
-
sourcecode --agent
|
|
594
|
+
sourcecode --compact high-signal summary (recommended)
|
|
595
|
+
sourcecode --compact --git-context include git hotspots
|
|
596
|
+
sourcecode /path/to/repo --compact analyze specific path
|
|
597
|
+
sourcecode --agent agent-optimized output (full detail)
|
|
593
598
|
"""
|
|
594
599
|
# First-run consent (skip for telemetry/version/config subcommands)
|
|
595
600
|
if ctx.invoked_subcommand not in ("telemetry", "version", "config"):
|
|
@@ -629,6 +634,10 @@ def main(
|
|
|
629
634
|
)
|
|
630
635
|
raise typer.Exit(code=1)
|
|
631
636
|
|
|
637
|
+
if symbol is not None and not symbol.strip():
|
|
638
|
+
typer.echo("symbol query cannot be empty", err=True)
|
|
639
|
+
raise typer.Exit(code=2)
|
|
640
|
+
|
|
632
641
|
if symbol and mode not in ("contract", "standard"):
|
|
633
642
|
typer.echo(
|
|
634
643
|
f"Error: --symbol requires --mode contract or standard (got '{mode}'). "
|
|
@@ -760,6 +769,16 @@ def main(
|
|
|
760
769
|
_java_min_depth = 12
|
|
761
770
|
effective_depth = max(depth, _java_min_depth) if _is_java and depth < _java_min_depth else depth
|
|
762
771
|
|
|
772
|
+
if symbol is not None and _is_java:
|
|
773
|
+
typer.echo(
|
|
774
|
+
f"Error: --symbol is not supported for Java/JVM repositories. "
|
|
775
|
+
"Per-file AST extraction is unavailable for JVM — symbol search only works with Python, TypeScript, and JavaScript. "
|
|
776
|
+
"Alternatives: use --agent --compact to get file relevance scores, "
|
|
777
|
+
"or use --git-context to find recently changed files.",
|
|
778
|
+
err=True,
|
|
779
|
+
)
|
|
780
|
+
raise typer.Exit(code=1)
|
|
781
|
+
|
|
763
782
|
# --agent: enable signal analyzers; output via agent_view (not compact)
|
|
764
783
|
if agent:
|
|
765
784
|
dependencies = True
|
|
@@ -1485,7 +1504,9 @@ def main(
|
|
|
1485
1504
|
if _is_contract_mode and sm.file_contracts:
|
|
1486
1505
|
from sourcecode.serializer import _serialize_contract_minimal
|
|
1487
1506
|
data.pop("file_relevance", None)
|
|
1488
|
-
|
|
1507
|
+
_jvm_stacks_agent = {"java", "kotlin", "scala", "groovy"}
|
|
1508
|
+
_is_jvm_agent = any(s.stack in _jvm_stacks_agent for s in sm.stacks)
|
|
1509
|
+
_MAX_AGENT_CONTRACTS = 50 if _is_jvm_agent else 10
|
|
1489
1510
|
_all_contracts = sm.file_contracts
|
|
1490
1511
|
_sorted = sorted(_all_contracts, key=lambda c: getattr(c, "relevance_score", 0.0), reverse=True)
|
|
1491
1512
|
_sampled = _sorted[:_MAX_AGENT_CONTRACTS]
|
|
@@ -41,6 +41,34 @@ _M3_FILTRO_PARAMS_RE = re.compile(
|
|
|
41
41
|
r'(?:[^)]*nivelRequerido\s*=\s*(\d+))?'
|
|
42
42
|
)
|
|
43
43
|
|
|
44
|
+
# Security config detection
|
|
45
|
+
_WEB_SECURITY_CONFIGURER_RE = re.compile(r'WebSecurityConfigurerAdapter\b')
|
|
46
|
+
_SECURITY_FILTER_CHAIN_RE = re.compile(r'SecurityFilterChain\b')
|
|
47
|
+
_SECURITY_CONFIG_ANNOTATION_RE = re.compile(r'@EnableWebSecurity\b')
|
|
48
|
+
# JWT/token filter detection (files that process every request)
|
|
49
|
+
_ONCE_PER_REQUEST_FILTER_RE = re.compile(r'extends\s+(?:OncePerRequestFilter|GenericFilterBean)\b')
|
|
50
|
+
_JWT_FILTER_KEYWORDS_RE = re.compile(r'\b(?:jwt|token|bearer|authorization)\b', re.IGNORECASE)
|
|
51
|
+
|
|
52
|
+
# @Transactional detection
|
|
53
|
+
_TRANSACTIONAL_RE = re.compile(r'@Transactional\b')
|
|
54
|
+
# Extracts class name: `public class Foo` or `class Foo`
|
|
55
|
+
_CLASS_NAME_RE = re.compile(r'\bclass\s+([A-Z][A-Za-z0-9_]*)')
|
|
56
|
+
|
|
57
|
+
# Gradle plugin Spring Boot version: id 'org.springframework.boot' version '2.6.3'
|
|
58
|
+
_GRADLE_SB_PLUGIN_RE = re.compile(
|
|
59
|
+
r"""id\s*['"]\s*org\.springframework\.boot\s*['"]\s+version\s*['"]([\d.]+)['"']""",
|
|
60
|
+
re.IGNORECASE,
|
|
61
|
+
)
|
|
62
|
+
# Gradle Java version: sourceCompatibility = '11' or sourceCompatibility = JavaVersion.VERSION_11
|
|
63
|
+
_GRADLE_JAVA_VERSION_RE = re.compile(
|
|
64
|
+
r"""(?:sourceCompatibility|targetCompatibility|javaVersion)\s*=\s*['"]?([0-9.]+)['"]?""",
|
|
65
|
+
re.IGNORECASE,
|
|
66
|
+
)
|
|
67
|
+
# JavaVersion.VERSION_11 form
|
|
68
|
+
_GRADLE_JAVA_ENUM_RE = re.compile(
|
|
69
|
+
r"""(?:sourceCompatibility|targetCompatibility)\s*=\s*JavaVersion\.VERSION_(\d+)"""
|
|
70
|
+
)
|
|
71
|
+
|
|
44
72
|
|
|
45
73
|
class JavaDetector(AbstractDetector):
|
|
46
74
|
name = "java"
|
|
@@ -69,6 +97,12 @@ class JavaDetector(AbstractDetector):
|
|
|
69
97
|
if "build.gradle" in context.manifests:
|
|
70
98
|
manifests.append("build.gradle")
|
|
71
99
|
frameworks.extend(self._frameworks_from_gradle(context.root / "build.gradle"))
|
|
100
|
+
if language_version is None:
|
|
101
|
+
try:
|
|
102
|
+
gradle_content = "\n".join(read_text_lines(context.root / "build.gradle"))
|
|
103
|
+
language_version = self._extract_gradle_java_version(gradle_content)
|
|
104
|
+
except OSError:
|
|
105
|
+
pass
|
|
72
106
|
|
|
73
107
|
# Detect app server from descriptor files
|
|
74
108
|
all_paths = flatten_file_tree(context.file_tree)
|
|
@@ -81,6 +115,7 @@ class JavaDetector(AbstractDetector):
|
|
|
81
115
|
spring_profiles = self._detect_spring_profiles(context.root, all_paths)
|
|
82
116
|
|
|
83
117
|
entry_points = self._collect_entry_points(context)
|
|
118
|
+
transactional_classes = self._collect_transactional_classes(context, all_paths)
|
|
84
119
|
stack = StackDetection(
|
|
85
120
|
stack="java",
|
|
86
121
|
detection_method="manifest",
|
|
@@ -91,6 +126,7 @@ class JavaDetector(AbstractDetector):
|
|
|
91
126
|
packaging=packaging,
|
|
92
127
|
app_server_hint=app_server_hint,
|
|
93
128
|
spring_profiles=spring_profiles,
|
|
129
|
+
transactional_classes=transactional_classes,
|
|
94
130
|
)
|
|
95
131
|
return [stack], entry_points
|
|
96
132
|
|
|
@@ -196,8 +232,24 @@ class JavaDetector(AbstractDetector):
|
|
|
196
232
|
return frameworks
|
|
197
233
|
|
|
198
234
|
def _frameworks_from_gradle(self, path: Path) -> list[FrameworkDetection]:
|
|
199
|
-
|
|
200
|
-
|
|
235
|
+
original = "\n".join(read_text_lines(path))
|
|
236
|
+
content = original.lower()
|
|
237
|
+
sb_version = self._extract_gradle_sb_version(original)
|
|
238
|
+
return self._detect_jvm_frameworks(content, "build.gradle", sb_version=sb_version)
|
|
239
|
+
|
|
240
|
+
def _extract_gradle_sb_version(self, content: str) -> str | None:
|
|
241
|
+
m = _GRADLE_SB_PLUGIN_RE.search(content)
|
|
242
|
+
return m.group(1) if m else None
|
|
243
|
+
|
|
244
|
+
def _extract_gradle_java_version(self, content: str) -> str | None:
|
|
245
|
+
m = _GRADLE_JAVA_ENUM_RE.search(content)
|
|
246
|
+
if m:
|
|
247
|
+
v = m.group(1)
|
|
248
|
+
return "1." + v if int(v) <= 8 else v
|
|
249
|
+
m = _GRADLE_JAVA_VERSION_RE.search(content)
|
|
250
|
+
if m:
|
|
251
|
+
return m.group(1)
|
|
252
|
+
return None
|
|
201
253
|
|
|
202
254
|
def _detect_jvm_frameworks(self, text: str, source: str, *, sb_version: str | None = None) -> list[FrameworkDetection]:
|
|
203
255
|
frameworks: list[FrameworkDetection] = []
|
|
@@ -319,7 +371,11 @@ class JavaDetector(AbstractDetector):
|
|
|
319
371
|
return []
|
|
320
372
|
|
|
321
373
|
# Quick pre-filter before running regexes
|
|
322
|
-
|
|
374
|
+
has_controller = "Controller" in content
|
|
375
|
+
has_filter = "Filter" in content
|
|
376
|
+
has_security = "WebSecurityConfigurerAdapter" in content or "SecurityFilterChain" in content or "EnableWebSecurity" in content
|
|
377
|
+
has_once_filter = "OncePerRequestFilter" in content or "GenericFilterBean" in content
|
|
378
|
+
if (not has_controller and not has_filter and not has_security
|
|
323
379
|
and "ControllerAdvice" not in content
|
|
324
380
|
and "M3FiltroSeguridad" not in content):
|
|
325
381
|
return []
|
|
@@ -379,6 +435,23 @@ class JavaDetector(AbstractDetector):
|
|
|
379
435
|
path=rel_path, stack="java", kind="filter",
|
|
380
436
|
source="annotation", confidence="medium",
|
|
381
437
|
)]
|
|
438
|
+
if has_security and (
|
|
439
|
+
_WEB_SECURITY_CONFIGURER_RE.search(content)
|
|
440
|
+
or _SECURITY_CONFIG_ANNOTATION_RE.search(content)
|
|
441
|
+
or _SECURITY_FILTER_CHAIN_RE.search(content)
|
|
442
|
+
):
|
|
443
|
+
return [EntryPoint(
|
|
444
|
+
path=rel_path, stack="java", kind="security_config",
|
|
445
|
+
source="annotation", confidence="high",
|
|
446
|
+
evidence="Spring Security configuration",
|
|
447
|
+
)]
|
|
448
|
+
if has_once_filter and _ONCE_PER_REQUEST_FILTER_RE.search(content):
|
|
449
|
+
is_jwt = bool(_JWT_FILTER_KEYWORDS_RE.search(content))
|
|
450
|
+
return [EntryPoint(
|
|
451
|
+
path=rel_path, stack="java", kind="security_filter",
|
|
452
|
+
source="annotation", confidence="high",
|
|
453
|
+
evidence="jwt_filter" if is_jwt else "request_filter",
|
|
454
|
+
)]
|
|
382
455
|
return []
|
|
383
456
|
|
|
384
457
|
def _parse_web_xml(self, abs_path: Path, rel_path: str) -> list[EntryPoint]:
|
|
@@ -412,3 +485,26 @@ class JavaDetector(AbstractDetector):
|
|
|
412
485
|
seen.add(framework.name)
|
|
413
486
|
result.append(framework)
|
|
414
487
|
return result
|
|
488
|
+
|
|
489
|
+
def _collect_transactional_classes(self, context: DetectionContext, all_paths: list[str]) -> list[str]:
|
|
490
|
+
"""Scan Java source files for @Transactional and return unique class names."""
|
|
491
|
+
classes: list[str] = []
|
|
492
|
+
seen: set[str] = set()
|
|
493
|
+
java_paths = [p for p in all_paths if p.endswith(".java") and "/test/" not in p and "/tests/" not in p]
|
|
494
|
+
for rel_path in java_paths[:_MAX_JAVA_ENTRY_SCAN]:
|
|
495
|
+
abs_path = context.root / rel_path
|
|
496
|
+
try:
|
|
497
|
+
if abs_path.stat().st_size > _MAX_FILE_SIZE:
|
|
498
|
+
continue
|
|
499
|
+
content = abs_path.read_text(encoding="utf-8", errors="replace")
|
|
500
|
+
except OSError:
|
|
501
|
+
continue
|
|
502
|
+
if not _TRANSACTIONAL_RE.search(content):
|
|
503
|
+
continue
|
|
504
|
+
m = _CLASS_NAME_RE.search(content)
|
|
505
|
+
if m:
|
|
506
|
+
cls = m.group(1)
|
|
507
|
+
if cls not in seen:
|
|
508
|
+
seen.add(cls)
|
|
509
|
+
classes.append(cls)
|
|
510
|
+
return classes
|
|
@@ -121,6 +121,7 @@ class ProjectDetector:
|
|
|
121
121
|
packaging=stack.packaging,
|
|
122
122
|
app_server_hint=stack.app_server_hint,
|
|
123
123
|
spring_profiles=list(stack.spring_profiles),
|
|
124
|
+
transactional_classes=list(stack.transactional_classes),
|
|
124
125
|
)
|
|
125
126
|
|
|
126
127
|
def _merge_stack(self, current: StackDetection, incoming: StackDetection) -> StackDetection:
|
|
@@ -144,6 +145,8 @@ class ProjectDetector:
|
|
|
144
145
|
current.app_server_hint = incoming.app_server_hint
|
|
145
146
|
if incoming.spring_profiles and not current.spring_profiles:
|
|
146
147
|
current.spring_profiles = list(incoming.spring_profiles)
|
|
148
|
+
if incoming.transactional_classes and not current.transactional_classes:
|
|
149
|
+
current.transactional_classes = list(incoming.transactional_classes)
|
|
147
150
|
return current
|
|
148
151
|
|
|
149
152
|
def _merge_frameworks(
|
|
@@ -563,6 +563,25 @@ class TaskContextBuilder:
|
|
|
563
563
|
except Exception:
|
|
564
564
|
pass
|
|
565
565
|
|
|
566
|
+
# ── 5c. review-pr suspected_areas (needs git uncommitted_files) ──────
|
|
567
|
+
if task_name == "review-pr" and spec.enable_code_notes:
|
|
568
|
+
pr_areas: dict[str, int] = {}
|
|
569
|
+
for path in uncommitted_files:
|
|
570
|
+
pr_areas[path] = pr_areas.get(path, 0) + 10
|
|
571
|
+
review_kinds = {"FIXME", "TODO", "BUG", "HACK"}
|
|
572
|
+
for note in cn_notes_for_ranking:
|
|
573
|
+
if note.kind in review_kinds:
|
|
574
|
+
pr_areas[note.path] = pr_areas.get(note.path, 0) + 1
|
|
575
|
+
_BOOST_STEMS = ("Controller", "Service", "Repository", "Mapper", "Filter", "Security")
|
|
576
|
+
for path in all_paths:
|
|
577
|
+
stem = Path(path).stem
|
|
578
|
+
if any(k in stem for k in _BOOST_STEMS):
|
|
579
|
+
pr_areas[path] = pr_areas.get(path, 0) + 2
|
|
580
|
+
suspected_areas = [
|
|
581
|
+
p for p, _ in sorted(pr_areas.items(), key=lambda x: -x[1])[:8]
|
|
582
|
+
if not self._is_test(p)
|
|
583
|
+
]
|
|
584
|
+
|
|
566
585
|
# ── 6. Rank files ──────────────────────────────────────────────────
|
|
567
586
|
entry_set = {ep.path for ep in entry_points}
|
|
568
587
|
test_set = {p for p in all_paths if self._is_test(p)}
|
|
@@ -68,6 +68,7 @@ class StackDetection:
|
|
|
68
68
|
packaging: Optional[str] = None # e.g. "war" | "jar"
|
|
69
69
|
app_server_hint: Optional[str] = None # e.g. "weblogic" | "wildfly"
|
|
70
70
|
spring_profiles: list[str] = field(default_factory=list) # detected Spring profiles
|
|
71
|
+
transactional_classes: list[str] = field(default_factory=list) # classes with @Transactional
|
|
71
72
|
|
|
72
73
|
|
|
73
74
|
@dataclass
|