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.

Files changed (189) hide show
  1. {sourcecode-1.16.0 → sourcecode-1.18.0}/PKG-INFO +3 -3
  2. {sourcecode-1.16.0 → sourcecode-1.18.0}/README.md +2 -2
  3. {sourcecode-1.16.0 → sourcecode-1.18.0}/pyproject.toml +1 -1
  4. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/cli.py +32 -9
  6. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/java.py +10 -0
  7. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/prepare_context.py +64 -4
  8. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/serializer.py +116 -26
  9. {sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  10. {sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  11. {sourcecode-1.16.0 → sourcecode-1.18.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  12. {sourcecode-1.16.0 → sourcecode-1.18.0}/.continue-here.md +0 -0
  13. {sourcecode-1.16.0 → sourcecode-1.18.0}/.github/workflows/build-windows.yml +0 -0
  14. {sourcecode-1.16.0 → sourcecode-1.18.0}/.gitignore +0 -0
  15. {sourcecode-1.16.0 → sourcecode-1.18.0}/.ruff.toml +0 -0
  16. {sourcecode-1.16.0 → sourcecode-1.18.0}/CONTRIBUTING.md +0 -0
  17. {sourcecode-1.16.0 → sourcecode-1.18.0}/LICENSE +0 -0
  18. {sourcecode-1.16.0 → sourcecode-1.18.0}/SECURITY.md +0 -0
  19. {sourcecode-1.16.0 → sourcecode-1.18.0}/docs/privacy.md +0 -0
  20. {sourcecode-1.16.0 → sourcecode-1.18.0}/docs/schema.md +0 -0
  21. {sourcecode-1.16.0 → sourcecode-1.18.0}/raw +0 -0
  22. {sourcecode-1.16.0 → sourcecode-1.18.0}/run_cli.py +0 -0
  23. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/adaptive_scanner.py +0 -0
  24. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/architecture_analyzer.py +0 -0
  25. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/architecture_summary.py +0 -0
  26. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/ast_extractor.py +0 -0
  27. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/classifier.py +0 -0
  28. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  29. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/confidence_analyzer.py +0 -0
  30. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/context_scorer.py +0 -0
  31. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/context_summarizer.py +0 -0
  32. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/contract_model.py +0 -0
  33. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/contract_pipeline.py +0 -0
  34. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/coverage_parser.py +0 -0
  35. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/dependency_analyzer.py +0 -0
  36. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/__init__.py +0 -0
  37. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/base.py +0 -0
  38. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  39. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/dart.py +0 -0
  40. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/dotnet.py +0 -0
  41. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/elixir.py +0 -0
  42. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/go.py +0 -0
  43. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/heuristic.py +0 -0
  44. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/hybrid.py +0 -0
  45. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  46. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/nodejs.py +0 -0
  47. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/parsers.py +0 -0
  48. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/php.py +0 -0
  49. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/project.py +0 -0
  50. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/python.py +0 -0
  51. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/ruby.py +0 -0
  52. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/rust.py +0 -0
  53. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/systems.py +0 -0
  54. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/terraform.py +0 -0
  55. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/detectors/tooling.py +0 -0
  56. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/doc_analyzer.py +0 -0
  57. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  58. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/env_analyzer.py +0 -0
  59. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/file_classifier.py +0 -0
  60. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/git_analyzer.py +0 -0
  61. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/graph_analyzer.py +0 -0
  62. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/metrics_analyzer.py +0 -0
  63. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/progress.py +0 -0
  64. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/ranking_engine.py +0 -0
  65. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/redactor.py +0 -0
  66. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/relevance_scorer.py +0 -0
  67. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/repo_classifier.py +0 -0
  68. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/runtime_classifier.py +0 -0
  69. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/scanner.py +0 -0
  70. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/schema.py +0 -0
  71. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/semantic_analyzer.py +0 -0
  72. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/summarizer.py +0 -0
  73. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/__init__.py +0 -0
  74. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/config.py +0 -0
  75. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/consent.py +0 -0
  76. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/events.py +0 -0
  77. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/filters.py +0 -0
  78. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/telemetry/transport.py +0 -0
  79. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/tree_utils.py +0 -0
  80. {sourcecode-1.16.0 → sourcecode-1.18.0}/src/sourcecode/workspace.py +0 -0
  81. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/__init__.py +0 -0
  82. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/conftest.py +0 -0
  83. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/coverage.xml +0 -0
  84. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  85. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  86. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  87. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/go_service/go.mod +0 -0
  88. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/jacoco.xml +0 -0
  89. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/latin1_sample.java +0 -0
  90. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/latin1_sample_iso.java +0 -0
  91. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/lcov.info +0 -0
  92. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  93. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/nextjs_app/package.json +0 -0
  94. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  95. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  96. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  97. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  98. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  99. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  100. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  101. {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
  102. {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
  103. {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
  104. {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
  105. {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
  106. {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
  107. {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
  108. {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
  109. {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
  110. {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
  111. {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
  112. {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
  113. {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
  114. {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
  115. {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
  116. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  117. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
  118. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  119. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  120. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  121. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  122. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  123. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
  124. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  125. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  126. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
  127. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_architecture_analyzer.py +0 -0
  128. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_architecture_summary.py +0 -0
  129. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_ast_extractor.py +0 -0
  130. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_block1_reliability.py +0 -0
  131. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_block2_coverage.py +0 -0
  132. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_block5_quality.py +0 -0
  133. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_bug_fixes_v16.py +0 -0
  134. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_classifier.py +0 -0
  135. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_cli.py +0 -0
  136. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_code_notes_analyzer.py +0 -0
  137. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_context_scorer.py +0 -0
  138. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_contract_pipeline.py +0 -0
  139. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_coverage_parser.py +0 -0
  140. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_cross_consistency.py +0 -0
  141. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_dependency_analyzer_node_python.py +0 -0
  142. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  143. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_dependency_schema.py +0 -0
  144. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_dotnet.py +0 -0
  145. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_go_rust_java.py +0 -0
  146. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_nodejs.py +0 -0
  147. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_php_ruby_dart.py +0 -0
  148. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_python.py +0 -0
  149. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_universal_managed.py +0 -0
  150. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detector_universal_systems.py +0 -0
  151. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_detectors_base.py +0 -0
  152. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  153. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_doc_analyzer_python.py +0 -0
  154. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_encoding_regression.py +0 -0
  155. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  156. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_graph_analyzer_python_node.py +0 -0
  157. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_graph_schema.py +0 -0
  158. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_hybrid_inference.py +0 -0
  159. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration.py +0 -0
  160. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_dependencies.py +0 -0
  161. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_detection.py +0 -0
  162. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_docs.py +0 -0
  163. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_graph_modules.py +0 -0
  164. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_lqn.py +0 -0
  165. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_metrics.py +0 -0
  166. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_multistack.py +0 -0
  167. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_semantics.py +0 -0
  168. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_integration_universal.py +0 -0
  169. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_java_spring_integration.py +0 -0
  170. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_metrics_analyzer.py +0 -0
  171. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_packaging.py +0 -0
  172. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_phase1_improvements.py +0 -0
  173. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_pipeline_integrity.py +0 -0
  174. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_real_projects.py +0 -0
  175. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_redactor.py +0 -0
  176. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_scanner.py +0 -0
  177. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_schema.py +0 -0
  178. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_schema_normalization.py +0 -0
  179. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_analyzer_node.py +0 -0
  180. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_analyzer_python.py +0 -0
  181. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_import_resolution.py +0 -0
  182. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_semantic_schema.py +0 -0
  183. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_signal_hierarchy.py +0 -0
  184. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_summarizer.py +0 -0
  185. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_surface_honesty.py +0 -0
  186. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_task_differentiation.py +0 -0
  187. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_telemetry.py +0 -0
  188. {sourcecode-1.16.0 → sourcecode-1.18.0}/tests/test_v1_10_regressions.py +0 -0
  189. {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.16.0
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
- ![Version](https://img.shields.io/badge/version-1.16.0-blue)
224
+ ![Version](https://img.shields.io/badge/version-1.18.0-blue)
225
225
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
226
226
 
227
227
  ---
@@ -255,7 +255,7 @@ pipx install sourcecode
255
255
 
256
256
  ```bash
257
257
  sourcecode version
258
- # sourcecode 1.16.0
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
- ![Version](https://img.shields.io/badge/version-1.16.0-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.18.0-blue)
6
6
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
7
7
 
8
8
  ---
@@ -36,7 +36,7 @@ pipx install sourcecode
36
36
 
37
37
  ```bash
38
38
  sourcecode version
39
- # sourcecode 1.16.0
39
+ # sourcecode 1.18.0
40
40
  ```
41
41
 
42
42
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.16.0"
7
+ version = "1.18.0"
8
8
  description = "Deterministic codebase context for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.16.0"
3
+ __version__ = "1.18.0"
@@ -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
- _pc_bytes = _pc_content.encode("utf-8")
1766
- _sys.stdout.buffer.write(_pc_bytes)
1767
- if not _pc_content.endswith("\n"):
1768
- _sys.stdout.buffer.write(b"\n")
1769
- _sys.stdout.buffer.flush()
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
- result["dto_mappers"] = dto_mappers[:10]
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 name contains a profile name (case-insensitive)
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
- matches = [
379
- p for p in sm.file_paths
380
- if pfx in Path(p).stem.lower() and p.endswith(".java")
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 for complete list"
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 _security_surface_from_eps(eps: list) -> "Optional[dict[str, Any]]":
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 and nm not in seen:
429
- seen.add(nm)
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
- return {
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", "")[:60]} if getattr(n, "text", "") else {}),
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 = {"overall": cs.overall, "stack": cs.stack_confidence, "entry_points": cs.entry_point_confidence}
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
- _security_surface = _security_surface_from_eps(sm.entry_points)
991
- _mybatis = _mybatis_pairing(sm)
992
- _transactional = _transactional_summary(sm)
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
- _sec_surf = _security_surface_from_eps(sm.entry_points)
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
 
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