sourcecode 1.16.0__tar.gz → 1.18.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.
Potentially problematic release.
This version of sourcecode might be problematic. Click here for more details.
- {sourcecode-1.16.0 → sourcecode-1.18.0}/PKG-INFO +3 -3
- {sourcecode-1.16.0 → sourcecode-1.18.0}/README.md +2 -2
- {sourcecode-1.16.0 → sourcecode-1.18.0}/pyproject.toml +1 -1
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/cli.py +32 -9
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/java.py +10 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/prepare_context.py +64 -4
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/serializer.py +116 -26
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.continue-here.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.gitignore +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/.ruff.toml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/CONTRIBUTING.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/LICENSE +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/SECURITY.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/docs/privacy.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/docs/schema.md +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/raw +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/run_cli.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/__init__.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/conftest.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/latin1_sample.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/latin1_sample_iso.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_bug_fixes_v16.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_classifier.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_cli.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_python.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_encoding_regression.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_packaging.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_real_projects.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_redactor.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_scanner.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_schema.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_summarizer.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_surface_honesty.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_task_differentiation.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_telemetry.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_v1_10_regressions.py +0 -0
- {sourcecode-1.16.0 → sourcecode-1.18.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.18.0
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -221,7 +221,7 @@ Description-Content-Type: text/markdown
|
|
|
221
221
|
|
|
222
222
|
**Compressed AI-ready context for Java/Spring enterprise codebases.**
|
|
223
223
|
|
|
224
|
-

|
|
225
225
|

|
|
226
226
|
|
|
227
227
|
---
|
|
@@ -255,7 +255,7 @@ pipx install sourcecode
|
|
|
255
255
|
|
|
256
256
|
```bash
|
|
257
257
|
sourcecode version
|
|
258
|
-
# sourcecode 1.
|
|
258
|
+
# sourcecode 1.18.0
|
|
259
259
|
```
|
|
260
260
|
|
|
261
261
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Compressed AI-ready context for Java/Spring enterprise codebases.**
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|

|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -36,7 +36,7 @@ pipx install sourcecode
|
|
|
36
36
|
|
|
37
37
|
```bash
|
|
38
38
|
sourcecode version
|
|
39
|
-
# sourcecode 1.
|
|
39
|
+
# sourcecode 1.18.0
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
---
|
|
@@ -511,6 +511,11 @@ def main(
|
|
|
511
511
|
"--agent",
|
|
512
512
|
help="Structured noise-free JSON for AI agents: identity, entry points, dependencies, confidence, gaps.",
|
|
513
513
|
),
|
|
514
|
+
full: bool = typer.Option(
|
|
515
|
+
False,
|
|
516
|
+
"--full",
|
|
517
|
+
help="Remove truncation limits on transactional_boundaries, mybatis.dto_mappers, and other capped lists.",
|
|
518
|
+
),
|
|
514
519
|
trace_pipeline: bool = typer.Option(
|
|
515
520
|
False,
|
|
516
521
|
"--trace-pipeline",
|
|
@@ -1504,12 +1509,12 @@ def main(
|
|
|
1504
1509
|
else:
|
|
1505
1510
|
content = json.dumps(data, indent=2, ensure_ascii=False)
|
|
1506
1511
|
elif agent:
|
|
1507
|
-
data = agent_view(sm)
|
|
1512
|
+
data = agent_view(sm, full=full)
|
|
1508
1513
|
if not no_redact:
|
|
1509
1514
|
data = redact_dict(data)
|
|
1510
1515
|
content = json.dumps(data, indent=2, ensure_ascii=False)
|
|
1511
1516
|
elif compact:
|
|
1512
|
-
data = compact_view(sm, no_tree=no_tree)
|
|
1517
|
+
data = compact_view(sm, no_tree=no_tree, full=full)
|
|
1513
1518
|
if not no_redact:
|
|
1514
1519
|
data = redact_dict(data)
|
|
1515
1520
|
content = json.dumps(data, indent=2, ensure_ascii=False)
|
|
@@ -1607,6 +1612,17 @@ def prepare_context_cmd(
|
|
|
1607
1612
|
"-c",
|
|
1608
1613
|
help="Copy output to system clipboard after a successful run. No-op when clipboard is unavailable.",
|
|
1609
1614
|
),
|
|
1615
|
+
output_path: Optional[Path] = typer.Option(
|
|
1616
|
+
None,
|
|
1617
|
+
"--output",
|
|
1618
|
+
"-o",
|
|
1619
|
+
help="Write output to a file instead of stdout (UTF-8, avoids PowerShell BOM on Windows).",
|
|
1620
|
+
),
|
|
1621
|
+
symptom: Optional[str] = typer.Option(
|
|
1622
|
+
None,
|
|
1623
|
+
"--symptom",
|
|
1624
|
+
help="(fix-bug) Keyword hint for the bug: boosts matching files and surfaces related code notes.",
|
|
1625
|
+
),
|
|
1610
1626
|
) -> None:
|
|
1611
1627
|
"""Task-specific context for AI coding agents.
|
|
1612
1628
|
|
|
@@ -1673,7 +1689,7 @@ def prepare_context_cmd(
|
|
|
1673
1689
|
from dataclasses import asdict
|
|
1674
1690
|
|
|
1675
1691
|
builder = TaskContextBuilder(target)
|
|
1676
|
-
output = builder.build(task, since=since)
|
|
1692
|
+
output = builder.build(task, since=since, symptom=symptom)
|
|
1677
1693
|
|
|
1678
1694
|
# Task-specific content-filter: each task emphasizes different output fields.
|
|
1679
1695
|
# Fields marked False are suppressed from this task's output to reduce noise.
|
|
@@ -1757,16 +1773,23 @@ def prepare_context_cmd(
|
|
|
1757
1773
|
out["affected_entry_points"] = output.affected_entry_points
|
|
1758
1774
|
if output.limitations:
|
|
1759
1775
|
out["limitations"] = output.limitations
|
|
1776
|
+
if output.symptom:
|
|
1777
|
+
out["symptom"] = output.symptom
|
|
1778
|
+
if output.related_notes:
|
|
1779
|
+
out["related_notes"] = output.related_notes
|
|
1760
1780
|
if llm_prompt:
|
|
1761
1781
|
out["llm_prompt"] = builder.render_prompt(output)
|
|
1762
1782
|
|
|
1763
|
-
import sys as _sys
|
|
1764
1783
|
_pc_content = json.dumps(out, indent=2, ensure_ascii=False)
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
_sys
|
|
1769
|
-
|
|
1784
|
+
if output_path is not None:
|
|
1785
|
+
output_path.write_text(_pc_content, encoding="utf-8")
|
|
1786
|
+
else:
|
|
1787
|
+
import sys as _sys
|
|
1788
|
+
_pc_bytes = _pc_content.encode("utf-8")
|
|
1789
|
+
_sys.stdout.buffer.write(_pc_bytes)
|
|
1790
|
+
if not _pc_content.endswith("\n"):
|
|
1791
|
+
_sys.stdout.buffer.write(b"\n")
|
|
1792
|
+
_sys.stdout.buffer.flush()
|
|
1770
1793
|
|
|
1771
1794
|
if copy:
|
|
1772
1795
|
_trimmed = _pc_content.strip()
|
|
@@ -272,6 +272,16 @@ class JavaDetector(AbstractDetector):
|
|
|
272
272
|
frameworks.append(FrameworkDetection(name="Jakarta EE", source=source))
|
|
273
273
|
if "mybatis" in text:
|
|
274
274
|
frameworks.append(FrameworkDetection(name="MyBatis", source=source))
|
|
275
|
+
if "spring-boot-starter-security" in text or "spring-security-core" in text:
|
|
276
|
+
frameworks.append(FrameworkDetection(name="Spring Security", source=source))
|
|
277
|
+
if "spring-boot-starter-data-jpa" in text or "spring-data-jpa" in text:
|
|
278
|
+
frameworks.append(FrameworkDetection(name="Spring Data JPA", source=source))
|
|
279
|
+
if "spring-ldap-core" in text or "spring-security-ldap" in text:
|
|
280
|
+
frameworks.append(FrameworkDetection(name="Spring LDAP", source=source))
|
|
281
|
+
if "spring-aspects" in text or "spring-aop" in text:
|
|
282
|
+
frameworks.append(FrameworkDetection(name="Spring AOP", source=source))
|
|
283
|
+
if "spring-boot-starter-activemq" in text or "activemq-broker" in text or "activemq-client" in text:
|
|
284
|
+
frameworks.append(FrameworkDetection(name="ActiveMQ", source=source))
|
|
275
285
|
return frameworks
|
|
276
286
|
|
|
277
287
|
def _collect_entry_points(self, context: DetectionContext) -> list[EntryPoint]:
|
|
@@ -321,6 +321,8 @@ class TaskOutput:
|
|
|
321
321
|
why_these_files: dict[str, str] = field(default_factory=dict) # path → why relevant
|
|
322
322
|
changed_files: list[str] = field(default_factory=list) # delta task only
|
|
323
323
|
affected_entry_points: list[str] = field(default_factory=list) # delta task only
|
|
324
|
+
symptom: Optional[str] = None # fix-bug only
|
|
325
|
+
related_notes: list[dict] = field(default_factory=list) # fix-bug + symptom only
|
|
324
326
|
|
|
325
327
|
|
|
326
328
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -385,7 +387,7 @@ class TaskContextBuilder:
|
|
|
385
387
|
def __init__(self, root: Path) -> None:
|
|
386
388
|
self.root = root
|
|
387
389
|
|
|
388
|
-
def build(self, task_name: str, *, since: Optional[str] = None) -> TaskOutput:
|
|
390
|
+
def build(self, task_name: str, *, since: Optional[str] = None, symptom: Optional[str] = None) -> TaskOutput:
|
|
389
391
|
if task_name not in TASKS:
|
|
390
392
|
raise ValueError(
|
|
391
393
|
f"Unknown task '{task_name}'. Available: {', '.join(TASKS)}"
|
|
@@ -630,6 +632,56 @@ class TaskContextBuilder:
|
|
|
630
632
|
delta_files=_delta_files,
|
|
631
633
|
)
|
|
632
634
|
|
|
635
|
+
# ── 6b. Symptom keyword boost + related notes (fix-bug + --symptom) ──
|
|
636
|
+
symptom_keywords: list[str] = []
|
|
637
|
+
related_notes: list[dict] = []
|
|
638
|
+
if task_name == "fix-bug" and symptom:
|
|
639
|
+
import re as _re
|
|
640
|
+
symptom_keywords = [
|
|
641
|
+
w.lower() for w in _re.split(r"[\s\W]+", symptom)
|
|
642
|
+
if len(w) > 2
|
|
643
|
+
]
|
|
644
|
+
if symptom_keywords:
|
|
645
|
+
# Surface code notes whose text contains any keyword
|
|
646
|
+
for _n in cn_notes_for_ranking:
|
|
647
|
+
_text = (getattr(_n, "text", "") or "").lower()
|
|
648
|
+
if any(kw in _text for kw in symptom_keywords):
|
|
649
|
+
related_notes.append({
|
|
650
|
+
"kind": getattr(_n, "kind", ""),
|
|
651
|
+
"path": getattr(_n, "path", ""),
|
|
652
|
+
"line": getattr(_n, "line", None),
|
|
653
|
+
"text": getattr(_n, "text", ""),
|
|
654
|
+
})
|
|
655
|
+
# Secondary pass: inject files whose path matches symptom keywords
|
|
656
|
+
# but weren't in the candidate pool (no structural/git signals).
|
|
657
|
+
_existing_paths = {rf.path for rf in relevant_files}
|
|
658
|
+
for _p in all_paths:
|
|
659
|
+
if _p in _existing_paths:
|
|
660
|
+
continue
|
|
661
|
+
if Path(_p).suffix.lower() not in _ALL_EXTENSIONS:
|
|
662
|
+
continue
|
|
663
|
+
_p_lower = _p.lower()
|
|
664
|
+
_matching_kws = [kw for kw in symptom_keywords if kw in _p_lower]
|
|
665
|
+
if not _matching_kws:
|
|
666
|
+
continue
|
|
667
|
+
_boost = 0.2 * len(_matching_kws)
|
|
668
|
+
_injected_score = round(min(0.5 + _boost, 1.0), 2)
|
|
669
|
+
_first_kw = _matching_kws[0]
|
|
670
|
+
relevant_files.append(RelevantFile(
|
|
671
|
+
path=_p,
|
|
672
|
+
role="symptom_match",
|
|
673
|
+
score=_injected_score,
|
|
674
|
+
reason=f"path matches symptom keyword: {_first_kw}",
|
|
675
|
+
why=f"symptom injection: {', '.join(_matching_kws)}",
|
|
676
|
+
))
|
|
677
|
+
_existing_paths.add(_p)
|
|
678
|
+
|
|
679
|
+
# Re-rank all relevant_files: boost files whose path matches keywords
|
|
680
|
+
def _symptom_score(rf: "RelevantFile") -> float:
|
|
681
|
+
path_lower = rf.path.lower()
|
|
682
|
+
return rf.score + 0.2 * sum(1.0 for kw in symptom_keywords if kw in path_lower)
|
|
683
|
+
relevant_files = sorted(relevant_files, key=lambda rf: -_symptom_score(rf))
|
|
684
|
+
|
|
633
685
|
# ── 7. Test gaps (generate-tests only) ────────────────────────────
|
|
634
686
|
test_gaps: list[str] = []
|
|
635
687
|
if task_name == "generate-tests":
|
|
@@ -708,6 +760,8 @@ class TaskContextBuilder:
|
|
|
708
760
|
why_these_files=why_these_files,
|
|
709
761
|
changed_files=changed_files,
|
|
710
762
|
affected_entry_points=affected_entry_points,
|
|
763
|
+
symptom=symptom if task_name == "fix-bug" and symptom else None,
|
|
764
|
+
related_notes=related_notes,
|
|
711
765
|
)
|
|
712
766
|
|
|
713
767
|
def render_prompt(self, output: TaskOutput) -> str:
|
|
@@ -988,12 +1042,18 @@ class TaskContextBuilder:
|
|
|
988
1042
|
return Path(path).suffix.lower() in _SOURCE_EXTENSIONS
|
|
989
1043
|
|
|
990
1044
|
def _get_git_changed_files(self, since: Optional[str] = None) -> list[str]:
|
|
991
|
-
"""Get files changed since a git ref (default: HEAD~1) relative to root.
|
|
1045
|
+
"""Get files changed since a git ref (default: HEAD~1) relative to self.root.
|
|
1046
|
+
|
|
1047
|
+
Uses --relative so paths are relative to cwd (self.root), not the git repo
|
|
1048
|
+
root. This is critical for monorepos where self.root is a subpath of the
|
|
1049
|
+
git root and git diff would otherwise return prefixed paths that don't match
|
|
1050
|
+
the scanned file tree.
|
|
1051
|
+
"""
|
|
992
1052
|
import subprocess
|
|
993
1053
|
ref = since or "HEAD~1"
|
|
994
1054
|
try:
|
|
995
1055
|
result = subprocess.run(
|
|
996
|
-
["git", "diff", "--name-only", ref, "HEAD"],
|
|
1056
|
+
["git", "diff", "--name-only", "--relative", ref, "HEAD"],
|
|
997
1057
|
cwd=str(self.root),
|
|
998
1058
|
capture_output=True,
|
|
999
1059
|
text=True,
|
|
@@ -1011,7 +1071,7 @@ class TaskContextBuilder:
|
|
|
1011
1071
|
# Fallback: uncommitted changes
|
|
1012
1072
|
try:
|
|
1013
1073
|
result = subprocess.run(
|
|
1014
|
-
["git", "diff", "--name-only"],
|
|
1074
|
+
["git", "diff", "--name-only", "--relative"],
|
|
1015
1075
|
cwd=str(self.root),
|
|
1016
1076
|
capture_output=True,
|
|
1017
1077
|
text=True,
|
|
@@ -42,6 +42,14 @@ _MAX_DEFAULT_CONTRACTS = 20 # max contracts in default/standard contract output
|
|
|
42
42
|
_MAX_HARD_SIGNALS_DEFAULT = 20 # max hard_signals entries in default output
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
def _truncate_note(text: str, limit: int) -> str:
|
|
46
|
+
"""Truncate note text at word boundary, appending … when cut."""
|
|
47
|
+
if len(text) <= limit:
|
|
48
|
+
return text
|
|
49
|
+
cut = text[:limit].rsplit(" ", 1)[0]
|
|
50
|
+
return cut.rstrip(".,;") + "…"
|
|
51
|
+
|
|
52
|
+
|
|
45
53
|
def _cap_contracts_for_output(
|
|
46
54
|
contracts: list[Any],
|
|
47
55
|
max_count: int = _MAX_DEFAULT_CONTRACTS,
|
|
@@ -301,7 +309,7 @@ def _is_dto_mapper(path: str, root: Optional[Path] = None) -> bool:
|
|
|
301
309
|
return False
|
|
302
310
|
|
|
303
311
|
|
|
304
|
-
def _mybatis_pairing(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
312
|
+
def _mybatis_pairing(sm: "SourceMap", *, full: bool = False) -> "Optional[dict[str, Any]]":
|
|
305
313
|
"""Lightweight MyBatis mapper interface <-> XML file pairing from file_paths.
|
|
306
314
|
|
|
307
315
|
Separates genuine @Mapper interfaces (need XML) from DtoMapper bean-mapping
|
|
@@ -343,7 +351,11 @@ def _mybatis_pairing(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
|
343
351
|
if missing_xml:
|
|
344
352
|
result["missing_xml"] = missing_xml[:5]
|
|
345
353
|
if dto_mappers:
|
|
346
|
-
|
|
354
|
+
_total_dto = len(dto_mappers)
|
|
355
|
+
result["dto_mappers"] = dto_mappers if full else dto_mappers[:10]
|
|
356
|
+
result["dto_mappers_total"] = _total_dto
|
|
357
|
+
if _total_dto > 10 and not full:
|
|
358
|
+
result["dto_mappers_truncated"] = True
|
|
347
359
|
return result
|
|
348
360
|
|
|
349
361
|
|
|
@@ -371,16 +383,27 @@ def _spring_profiles_context(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
|
371
383
|
if not profiles:
|
|
372
384
|
return None
|
|
373
385
|
|
|
374
|
-
# Per-profile variants: Java files whose
|
|
386
|
+
# Per-profile variants: Java/XML files whose stem or path contains the profile name.
|
|
387
|
+
# Portal profiles (e.g. "ingesa-portal") use dash in directory/resource names but
|
|
388
|
+
# never in Java class names — match on full path instead of stem only.
|
|
375
389
|
per_profile: dict[str, list[str]] = {}
|
|
376
390
|
for profile in profiles:
|
|
377
391
|
pfx = profile.lower()
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
392
|
+
is_portal = "-" in profile
|
|
393
|
+
if is_portal:
|
|
394
|
+
matches = [
|
|
395
|
+
p for p in sm.file_paths
|
|
396
|
+
if pfx in p.lower() and (p.endswith(".java") or p.endswith(".xml"))
|
|
397
|
+
]
|
|
398
|
+
else:
|
|
399
|
+
matches = [
|
|
400
|
+
p for p in sm.file_paths
|
|
401
|
+
if pfx in Path(p).stem.lower() and p.endswith(".java")
|
|
402
|
+
]
|
|
382
403
|
if matches:
|
|
383
404
|
per_profile[profile] = [Path(p).name for p in matches[:5]]
|
|
405
|
+
elif is_portal:
|
|
406
|
+
per_profile[profile] = []
|
|
384
407
|
|
|
385
408
|
result: dict[str, Any] = {"detected": profiles}
|
|
386
409
|
if per_profile:
|
|
@@ -398,26 +421,63 @@ def _spring_profiles_context(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
|
398
421
|
return result
|
|
399
422
|
|
|
400
423
|
|
|
401
|
-
def _transactional_summary(sm: "SourceMap") -> "Optional[dict[str, Any]]":
|
|
424
|
+
def _transactional_summary(sm: "SourceMap", *, full: bool = False) -> "Optional[dict[str, Any]]":
|
|
402
425
|
"""Surface @Transactional class boundaries from the Java stack detection."""
|
|
403
426
|
for s in sm.stacks:
|
|
404
427
|
classes = getattr(s, "transactional_classes", [])
|
|
405
428
|
if classes:
|
|
406
429
|
total = len(classes)
|
|
407
430
|
result: dict[str, Any] = {"count": total, "classes": classes}
|
|
408
|
-
if total > 10:
|
|
431
|
+
if total > 10 and not full:
|
|
409
432
|
result["classes"] = classes[:10]
|
|
410
433
|
result["truncated"] = True
|
|
411
|
-
result["note"] = f"showing 10 of {total}; use --full
|
|
434
|
+
result["note"] = f"showing 10 of {total}; use --full to see all {total}"
|
|
412
435
|
return result
|
|
413
436
|
return None
|
|
414
437
|
|
|
415
438
|
|
|
416
|
-
def
|
|
439
|
+
def _resolve_java_constant(symbol: str, root: "Optional[Path]", file_paths: "Optional[list[str]]") -> str:
|
|
440
|
+
"""Resolve a Java constant reference like ClassName.FIELD_NAME to its string value."""
|
|
441
|
+
import re as _re
|
|
442
|
+
if not root or not file_paths or "." not in symbol:
|
|
443
|
+
return symbol
|
|
444
|
+
parts = symbol.rsplit(".", 1)
|
|
445
|
+
if len(parts) != 2:
|
|
446
|
+
return symbol
|
|
447
|
+
class_name, field_name = parts
|
|
448
|
+
if not class_name or not field_name or not field_name.isupper():
|
|
449
|
+
return symbol
|
|
450
|
+
target_file = f"{class_name}.java"
|
|
451
|
+
candidates = [p for p in file_paths if Path(p).name == target_file]
|
|
452
|
+
if not candidates:
|
|
453
|
+
return symbol
|
|
454
|
+
_CONST_RE = _re.compile(
|
|
455
|
+
r'\b' + _re.escape(field_name) + r'\s*=\s*"([^"]+)"'
|
|
456
|
+
)
|
|
457
|
+
for rel_path in candidates:
|
|
458
|
+
try:
|
|
459
|
+
abs_path = root / rel_path
|
|
460
|
+
content = abs_path.read_text(encoding="utf-8", errors="replace")
|
|
461
|
+
m = _CONST_RE.search(content)
|
|
462
|
+
if m:
|
|
463
|
+
return m.group(1)
|
|
464
|
+
except OSError:
|
|
465
|
+
continue
|
|
466
|
+
return symbol
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
def _security_surface_from_eps(
|
|
470
|
+
eps: list,
|
|
471
|
+
*,
|
|
472
|
+
root: "Optional[Path]" = None,
|
|
473
|
+
file_paths: "Optional[list[str]]" = None,
|
|
474
|
+
) -> "Optional[dict[str, Any]]":
|
|
417
475
|
"""Extract @M3FiltroSeguridad resource names from entry point evidence strings."""
|
|
418
476
|
import re as _re
|
|
419
477
|
_NOMBRE_RE = _re.compile(r"nombreRecurso=[\"']([^\"']+)[\"']")
|
|
478
|
+
_CONST_SYMBOL_RE = _re.compile(r'^[\w]+\.[\w]+$')
|
|
420
479
|
resource_names: list[str] = []
|
|
480
|
+
unresolved: list[str] = []
|
|
421
481
|
seen: set[str] = set()
|
|
422
482
|
for ep in eps:
|
|
423
483
|
evidence = getattr(ep, "evidence", None)
|
|
@@ -425,20 +485,30 @@ def _security_surface_from_eps(eps: list) -> "Optional[dict[str, Any]]":
|
|
|
425
485
|
continue
|
|
426
486
|
for m in _NOMBRE_RE.finditer(evidence):
|
|
427
487
|
nm = m.group(1)
|
|
428
|
-
if nm
|
|
429
|
-
|
|
488
|
+
if not nm or nm in seen:
|
|
489
|
+
continue
|
|
490
|
+
seen.add(nm)
|
|
491
|
+
if _CONST_SYMBOL_RE.match(nm):
|
|
492
|
+
resolved = _resolve_java_constant(nm, root, file_paths)
|
|
493
|
+
if resolved != nm:
|
|
494
|
+
resource_names.append(resolved)
|
|
495
|
+
else:
|
|
496
|
+
resource_names.append(nm)
|
|
497
|
+
unresolved.append(nm)
|
|
498
|
+
else:
|
|
430
499
|
resource_names.append(nm)
|
|
431
500
|
if not resource_names:
|
|
432
501
|
return None
|
|
433
|
-
|
|
502
|
+
result: dict[str, Any] = {
|
|
434
503
|
"schema": (
|
|
435
504
|
"Values used in @M3FiltroSeguridad(nombreRecurso=VALUE) on REST controller "
|
|
436
505
|
"methods. Each value names a permission resource checked at runtime."
|
|
437
506
|
),
|
|
438
|
-
# resource_names kept for backward compatibility; resources is the canonical key
|
|
439
507
|
"resource_names": resource_names,
|
|
440
|
-
"resources": resource_names,
|
|
441
508
|
}
|
|
509
|
+
if unresolved:
|
|
510
|
+
result["resource_names_unresolved"] = unresolved
|
|
511
|
+
return result
|
|
442
512
|
|
|
443
513
|
|
|
444
514
|
def _bootstrap_structured(eps: list) -> "Optional[dict[str, Any]]":
|
|
@@ -702,6 +772,7 @@ def _file_relevance(sm: SourceMap, *, limit: int = _FILE_RELEVANCE_LIMIT) -> lis
|
|
|
702
772
|
"category": file_class.category if file_class else "source",
|
|
703
773
|
"confidence": file_class.confidence if file_class else "low",
|
|
704
774
|
"relevance": relevance_val,
|
|
775
|
+
"score": relevance_val,
|
|
705
776
|
"reason": file_class.reason if file_class else (fs.reasons[0] if fs.reasons else "source file"),
|
|
706
777
|
"evidence": file_class.evidence if file_class else [],
|
|
707
778
|
}
|
|
@@ -712,6 +783,18 @@ def _file_relevance(sm: SourceMap, *, limit: int = _FILE_RELEVANCE_LIMIT) -> lis
|
|
|
712
783
|
if ranking_reasons:
|
|
713
784
|
item["ranking_reasons"] = ranking_reasons
|
|
714
785
|
|
|
786
|
+
# Override metadata for known M3 base controller classes
|
|
787
|
+
if any(k in stem for k in ("GenericRestController", "GenericCRUDRestController")):
|
|
788
|
+
item["category"] = "runtime_core"
|
|
789
|
+
item["relevance"] = 0.95
|
|
790
|
+
item["score"] = 0.95
|
|
791
|
+
item["reason"] = (
|
|
792
|
+
"base class for all REST controllers — extends this to get "
|
|
793
|
+
"centralized exception handling via handlerException()"
|
|
794
|
+
)
|
|
795
|
+
item["evidence"] = ["base_rest_controller"]
|
|
796
|
+
item["ranking_reasons"] = ["universal base class", "exception handling contract"]
|
|
797
|
+
|
|
715
798
|
scored.append((combined, item))
|
|
716
799
|
|
|
717
800
|
# Deterministic sort: score desc, then path asc
|
|
@@ -831,7 +914,7 @@ def _section_confidence(sm: SourceMap) -> dict[str, str]:
|
|
|
831
914
|
}
|
|
832
915
|
|
|
833
916
|
|
|
834
|
-
def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
917
|
+
def compact_view(sm: SourceMap, *, no_tree: bool = False, full: bool = False) -> dict[str, Any]:
|
|
835
918
|
"""Context package ready for prompt or handoff (~300-500 tokens).
|
|
836
919
|
|
|
837
920
|
Answers: what it is, where it enters, what depends on what,
|
|
@@ -914,7 +997,7 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
914
997
|
"kind": getattr(n, "kind", ""),
|
|
915
998
|
"path": getattr(n, "path", ""),
|
|
916
999
|
"line": getattr(n, "line", None),
|
|
917
|
-
**({"text": getattr(n, "text", "")
|
|
1000
|
+
**({"text": _truncate_note(getattr(n, "text", ""), 120)} if getattr(n, "text", "") else {}),
|
|
918
1001
|
}
|
|
919
1002
|
for n in _sorted_notes[:_CODE_NOTES_CAP]
|
|
920
1003
|
]
|
|
@@ -960,7 +1043,12 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
960
1043
|
conf_dict: Any = None
|
|
961
1044
|
if sm.confidence_summary is not None:
|
|
962
1045
|
cs = sm.confidence_summary
|
|
963
|
-
conf_dict = {
|
|
1046
|
+
conf_dict = {
|
|
1047
|
+
"overall": cs.overall,
|
|
1048
|
+
"stack": cs.stack_confidence,
|
|
1049
|
+
"entry_points": cs.entry_point_confidence,
|
|
1050
|
+
"sections": _section_confidence(sm),
|
|
1051
|
+
}
|
|
964
1052
|
if cs.anomalies:
|
|
965
1053
|
conf_dict["anomalies"] = cs.anomalies
|
|
966
1054
|
|
|
@@ -987,9 +1075,10 @@ def compact_view(sm: SourceMap, *, no_tree: bool = False) -> dict[str, Any]:
|
|
|
987
1075
|
if _app_server:
|
|
988
1076
|
_deployment["app_server_hint"] = _app_server
|
|
989
1077
|
_deploy_risks = _project_deployment_risks(sm)
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1078
|
+
_sec_root = Path(sm.metadata.analyzed_path) if sm.metadata.analyzed_path else None
|
|
1079
|
+
_security_surface = _security_surface_from_eps(sm.entry_points, root=_sec_root, file_paths=sm.file_paths)
|
|
1080
|
+
_mybatis = _mybatis_pairing(sm, full=full)
|
|
1081
|
+
_transactional = _transactional_summary(sm, full=full)
|
|
993
1082
|
_git_ctx = _compact_git_context(sm)
|
|
994
1083
|
_spring_profiles = _spring_profiles_context(sm)
|
|
995
1084
|
|
|
@@ -1321,7 +1410,7 @@ def validate_cross_analyzer_consistency(
|
|
|
1321
1410
|
return findings
|
|
1322
1411
|
|
|
1323
1412
|
|
|
1324
|
-
def agent_view(sm: SourceMap) -> dict[str, Any]:
|
|
1413
|
+
def agent_view(sm: SourceMap, *, full: bool = False) -> dict[str, Any]:
|
|
1325
1414
|
"""Opinionated output for AI agents — structured, noise-free, gap-aware.
|
|
1326
1415
|
|
|
1327
1416
|
Output order:
|
|
@@ -1505,13 +1594,14 @@ def agent_view(sm: SourceMap) -> dict[str, Any]:
|
|
|
1505
1594
|
signals["semantic_graph"] = sem_info
|
|
1506
1595
|
|
|
1507
1596
|
# Java/Spring: security surface, ORM structure, transactional boundaries
|
|
1508
|
-
|
|
1597
|
+
_av_root = Path(sm.metadata.analyzed_path) if sm.metadata.analyzed_path else None
|
|
1598
|
+
_sec_surf = _security_surface_from_eps(sm.entry_points, root=_av_root, file_paths=sm.file_paths)
|
|
1509
1599
|
if _sec_surf:
|
|
1510
1600
|
signals["security_surface"] = _sec_surf
|
|
1511
|
-
_mb = _mybatis_pairing(sm)
|
|
1601
|
+
_mb = _mybatis_pairing(sm, full=full)
|
|
1512
1602
|
if _mb:
|
|
1513
1603
|
signals["mybatis"] = _mb
|
|
1514
|
-
_txn = _transactional_summary(sm)
|
|
1604
|
+
_txn = _transactional_summary(sm, full=full)
|
|
1515
1605
|
if _txn:
|
|
1516
1606
|
signals["transactional_boundaries"] = _txn
|
|
1517
1607
|
|
{sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md
RENAMED
|
File without changes
|
{sourcecode-1.16.0 → sourcecode-1.18.0}/.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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|