sourcecode 1.4.0__tar.gz → 1.5.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.
Files changed (177) hide show
  1. {sourcecode-1.4.0 → sourcecode-1.5.0}/PKG-INFO +1 -1
  2. {sourcecode-1.4.0 → sourcecode-1.5.0}/pyproject.toml +1 -1
  3. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/__init__.py +1 -1
  4. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/architecture_analyzer.py +12 -1
  5. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/ast_extractor.py +55 -0
  6. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/contract_pipeline.py +10 -1
  7. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/dependency_analyzer.py +12 -0
  8. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/java.py +7 -5
  9. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/serializer.py +27 -1
  10. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_contract_pipeline.py +4 -4
  11. {sourcecode-1.4.0 → sourcecode-1.5.0}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  12. {sourcecode-1.4.0 → sourcecode-1.5.0}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  13. {sourcecode-1.4.0 → sourcecode-1.5.0}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  14. {sourcecode-1.4.0 → sourcecode-1.5.0}/.github/workflows/build-windows.yml +0 -0
  15. {sourcecode-1.4.0 → sourcecode-1.5.0}/.gitignore +0 -0
  16. {sourcecode-1.4.0 → sourcecode-1.5.0}/.ruff.toml +0 -0
  17. {sourcecode-1.4.0 → sourcecode-1.5.0}/CONTRIBUTING.md +0 -0
  18. {sourcecode-1.4.0 → sourcecode-1.5.0}/LICENSE +0 -0
  19. {sourcecode-1.4.0 → sourcecode-1.5.0}/README.md +0 -0
  20. {sourcecode-1.4.0 → sourcecode-1.5.0}/SECURITY.md +0 -0
  21. {sourcecode-1.4.0 → sourcecode-1.5.0}/docs/privacy.md +0 -0
  22. {sourcecode-1.4.0 → sourcecode-1.5.0}/docs/schema.md +0 -0
  23. {sourcecode-1.4.0 → sourcecode-1.5.0}/raw +0 -0
  24. {sourcecode-1.4.0 → sourcecode-1.5.0}/run_cli.py +0 -0
  25. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/adaptive_scanner.py +0 -0
  26. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/architecture_summary.py +0 -0
  27. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/classifier.py +0 -0
  28. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/cli.py +0 -0
  29. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/code_notes_analyzer.py +0 -0
  30. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/confidence_analyzer.py +0 -0
  31. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/context_scorer.py +0 -0
  32. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/context_summarizer.py +0 -0
  33. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/contract_model.py +0 -0
  34. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/coverage_parser.py +0 -0
  35. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/__init__.py +0 -0
  36. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/base.py +0 -0
  37. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/csproj_parser.py +0 -0
  38. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/dart.py +0 -0
  39. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/dotnet.py +0 -0
  40. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/elixir.py +0 -0
  41. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/go.py +0 -0
  42. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/heuristic.py +0 -0
  43. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/hybrid.py +0 -0
  44. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/jvm_ext.py +0 -0
  45. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/nodejs.py +0 -0
  46. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/parsers.py +0 -0
  47. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/php.py +0 -0
  48. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/project.py +0 -0
  49. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/python.py +0 -0
  50. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/ruby.py +0 -0
  51. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/rust.py +0 -0
  52. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/systems.py +0 -0
  53. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/terraform.py +0 -0
  54. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/detectors/tooling.py +0 -0
  55. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/doc_analyzer.py +0 -0
  56. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/entrypoint_classifier.py +0 -0
  57. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/env_analyzer.py +0 -0
  58. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/file_classifier.py +0 -0
  59. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/git_analyzer.py +0 -0
  60. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/graph_analyzer.py +0 -0
  61. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/metrics_analyzer.py +0 -0
  62. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/prepare_context.py +0 -0
  63. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/ranking_engine.py +0 -0
  64. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/redactor.py +0 -0
  65. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/relevance_scorer.py +0 -0
  66. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/repo_classifier.py +0 -0
  67. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/runtime_classifier.py +0 -0
  68. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/scanner.py +0 -0
  69. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/schema.py +0 -0
  70. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/semantic_analyzer.py +0 -0
  71. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/summarizer.py +0 -0
  72. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/telemetry/__init__.py +0 -0
  73. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/telemetry/config.py +0 -0
  74. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/telemetry/consent.py +0 -0
  75. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/telemetry/events.py +0 -0
  76. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/telemetry/filters.py +0 -0
  77. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/telemetry/transport.py +0 -0
  78. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/tree_utils.py +0 -0
  79. {sourcecode-1.4.0 → sourcecode-1.5.0}/src/sourcecode/workspace.py +0 -0
  80. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/__init__.py +0 -0
  81. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/conftest.py +0 -0
  82. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/coverage.xml +0 -0
  83. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  84. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/fastapi_app/src/main.py +0 -0
  85. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  86. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/go_service/go.mod +0 -0
  87. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/jacoco.xml +0 -0
  88. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/lcov.info +0 -0
  89. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  90. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/nextjs_app/package.json +0 -0
  91. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  92. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  93. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  94. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  95. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  96. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  97. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  98. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
  99. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
  100. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
  101. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
  102. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
  103. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
  104. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
  105. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
  106. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
  107. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
  108. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
  109. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
  110. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
  111. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
  112. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
  113. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  114. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  115. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  116. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  117. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  118. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  119. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  120. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  121. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_architecture_analyzer.py +0 -0
  122. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_architecture_summary.py +0 -0
  123. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_ast_extractor.py +0 -0
  124. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_block1_reliability.py +0 -0
  125. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_block2_coverage.py +0 -0
  126. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_block5_quality.py +0 -0
  127. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_classifier.py +0 -0
  128. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_cli.py +0 -0
  129. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_code_notes_analyzer.py +0 -0
  130. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_context_scorer.py +0 -0
  131. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_coverage_parser.py +0 -0
  132. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_cross_consistency.py +0 -0
  133. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_dependency_analyzer_node_python.py +0 -0
  134. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_dependency_analyzer_polyglot.py +0 -0
  135. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_dependency_schema.py +0 -0
  136. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_dotnet.py +0 -0
  137. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_go_rust_java.py +0 -0
  138. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_nodejs.py +0 -0
  139. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_php_ruby_dart.py +0 -0
  140. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_python.py +0 -0
  141. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_universal_managed.py +0 -0
  142. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detector_universal_systems.py +0 -0
  143. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_detectors_base.py +0 -0
  144. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_doc_analyzer_jsdom.py +0 -0
  145. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_doc_analyzer_python.py +0 -0
  146. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_graph_analyzer_polyglot.py +0 -0
  147. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_graph_analyzer_python_node.py +0 -0
  148. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_graph_schema.py +0 -0
  149. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_hybrid_inference.py +0 -0
  150. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration.py +0 -0
  151. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_dependencies.py +0 -0
  152. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_detection.py +0 -0
  153. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_docs.py +0 -0
  154. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_graph_modules.py +0 -0
  155. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_lqn.py +0 -0
  156. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_metrics.py +0 -0
  157. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_multistack.py +0 -0
  158. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_semantics.py +0 -0
  159. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_integration_universal.py +0 -0
  160. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_java_spring_integration.py +0 -0
  161. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_metrics_analyzer.py +0 -0
  162. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_packaging.py +0 -0
  163. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_phase1_improvements.py +0 -0
  164. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_pipeline_integrity.py +0 -0
  165. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_real_projects.py +0 -0
  166. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_redactor.py +0 -0
  167. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_scanner.py +0 -0
  168. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_schema.py +0 -0
  169. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_schema_normalization.py +0 -0
  170. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_semantic_analyzer_node.py +0 -0
  171. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_semantic_analyzer_python.py +0 -0
  172. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_semantic_import_resolution.py +0 -0
  173. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_semantic_schema.py +0 -0
  174. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_signal_hierarchy.py +0 -0
  175. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_summarizer.py +0 -0
  176. {sourcecode-1.4.0 → sourcecode-1.5.0}/tests/test_telemetry.py +0 -0
  177. {sourcecode-1.4.0 → sourcecode-1.5.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.4.0
3
+ Version: 1.5.0
4
4
  Summary: Deterministic codebase context for AI coding agents
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.4.0"
7
+ version = "1.5.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.4.0"
3
+ __version__ = "1.5.0"
@@ -182,8 +182,19 @@ class ArchitectureAnalyzer:
182
182
  ddd_result = self._detect_ddd(sm.file_paths)
183
183
  if ddd_result is not None:
184
184
  ddd_pattern, ddd_layers, ddd_contexts, ddd_layer_names = ddd_result
185
- domains_for_ddd = self._cluster_domains(filtered) if len(filtered) >= 2 else []
186
185
  module_files = self._build_ddd_module_files(sm.file_paths, ddd_contexts)
186
+ # Use DDD bounded context names as domains so --architecture shows each
187
+ # context as a distinct domain instead of collapsing all files under
188
+ # the Maven path segment (e.g. "java").
189
+ domains_for_ddd = [
190
+ ArchitectureDomain(
191
+ name=n,
192
+ files=module_files.get(n, []),
193
+ role="DDD bounded context",
194
+ confidence="high",
195
+ )
196
+ for n in ddd_contexts
197
+ ]
187
198
  bc_list = [
188
199
  BoundedContext(name=n, modules=module_files.get(n, []), confidence="high")
189
200
  for n in ddd_contexts
@@ -1172,6 +1172,51 @@ def _detect_role(path: str, contract: FileContract) -> str:
1172
1172
  return "util"
1173
1173
 
1174
1174
 
1175
+ # ---------------------------------------------------------------------------
1176
+ # MyBatis XML mapper extractor
1177
+ # ---------------------------------------------------------------------------
1178
+
1179
+ def _extract_mybatis_xml(rel_path: str, source: str) -> FileContract:
1180
+ """Extract namespace and SQL operations from a MyBatis *Mapper.xml file."""
1181
+ import re as _re
1182
+ from xml.etree import ElementTree
1183
+
1184
+ _NS_STRIP = _re.compile(r"\{[^}]+\}")
1185
+ _SQL_OPS = frozenset({"select", "insert", "update", "delete"})
1186
+
1187
+ exports: list[ExportRecord] = []
1188
+ namespace: str | None = None
1189
+
1190
+ try:
1191
+ root_elem = ElementTree.fromstring(source.encode("utf-8"))
1192
+ namespace = root_elem.get("namespace") or None
1193
+ for elem in root_elem:
1194
+ tag = _NS_STRIP.sub("", elem.tag).lower()
1195
+ if tag in _SQL_OPS:
1196
+ op_id = (elem.get("id") or "").strip()
1197
+ if op_id:
1198
+ # type_ref carries select/insert/update/delete for the serializer
1199
+ exports.append(ExportRecord(kind="query", name=op_id, type_ref=tag))
1200
+ except Exception:
1201
+ return FileContract(
1202
+ path=rel_path,
1203
+ language="mybatis-xml",
1204
+ role="mybatis-mapper",
1205
+ extraction_method="heuristic",
1206
+ limitations=["xml_parse_error: failed to parse mapper XML"],
1207
+ )
1208
+
1209
+ deps = [f"namespace:{namespace}"] if namespace else []
1210
+ return FileContract(
1211
+ path=rel_path,
1212
+ language="mybatis-xml",
1213
+ role="mybatis-mapper",
1214
+ exports=exports,
1215
+ dependencies=deps,
1216
+ extraction_method="heuristic",
1217
+ )
1218
+
1219
+
1175
1220
  # ---------------------------------------------------------------------------
1176
1221
  # AstExtractor public class
1177
1222
  # ---------------------------------------------------------------------------
@@ -1191,6 +1236,16 @@ class AstExtractor:
1191
1236
  return self._ts_ok
1192
1237
 
1193
1238
  def extract(self, path: Path, root: Optional[Path] = None) -> Optional[FileContract]:
1239
+ # MyBatis mapper XML — handled before the language map lookup so .xml
1240
+ # files are only processed when they match the mapper naming convention.
1241
+ if path.suffix.lower() == ".xml" and path.name.endswith("Mapper.xml"):
1242
+ try:
1243
+ source = path.read_text(encoding="utf-8", errors="replace")
1244
+ except OSError:
1245
+ return None
1246
+ rel_path = str(path.relative_to(root)).replace("\\", "/") if root else path.name
1247
+ return _extract_mybatis_xml(rel_path, source)
1248
+
1194
1249
  ext = path.suffix.lower()
1195
1250
  language = _LANGUAGE_MAP.get(ext)
1196
1251
  if language is None:
@@ -219,9 +219,18 @@ class ContractPipeline:
219
219
  fname = Path(pn).name
220
220
  return any(fname.startswith(pat) or f".{pat.strip('.')}" in fname for pat in _TEST_PATTERNS)
221
221
 
222
+ def _is_extractable(p: str) -> bool:
223
+ suf = Path(p).suffix.lower()
224
+ if suf in _SRC_EXTENSIONS:
225
+ return True
226
+ # MyBatis mapper XML files — only *Mapper.xml, not all XML
227
+ if suf == ".xml" and p.endswith("Mapper.xml"):
228
+ return True
229
+ return False
230
+
222
231
  src_paths = [
223
232
  p for p in file_paths
224
- if Path(p).suffix.lower() in _SRC_EXTENSIONS
233
+ if _is_extractable(p)
225
234
  and not scorer.is_noise(p)
226
235
  and (symbol is not None or changed_only or not _is_test(p))
227
236
  ]
@@ -1191,6 +1191,18 @@ class DependencyAnalyzer:
1191
1191
  limitations: list[str] = []
1192
1192
  if not records:
1193
1193
  limitations.append("java: pom.xml sin dependencias parseables (puede usar BOM o propiedades)")
1194
+
1195
+ # Warn when Spring Boot BOM manages transitive deps — they can't be resolved statically.
1196
+ parent_artifact_local = (
1197
+ root_elem.findtext(f"{ns}parent/{ns}artifactId") or ""
1198
+ ).strip() if parent_elem is not None else ""
1199
+ if parent_artifact_local == "spring-boot-starter-parent" and parent_version:
1200
+ limitations.append(
1201
+ f"spring_boot_bom_detected: transitive deps managed by Spring Boot BOM "
1202
+ f"v{parent_version}, not resolved statically. "
1203
+ "Run 'mvn dependency:tree' for the full transitive tree."
1204
+ )
1205
+
1194
1206
  return records, limitations
1195
1207
 
1196
1208
  def _analyze_gradle(self, root: Path) -> tuple[list[DependencyRecord], list[str]]:
@@ -18,7 +18,7 @@ _NS_TAG_RE = re.compile(r"\{[^}]+\}")
18
18
 
19
19
  _MAX_FILE_SIZE = 256 * 1024 # 256 KB
20
20
  _MAX_JAVA_ENTRY_SCAN = 1000
21
- _MAX_ANNOTATION_ENTRY_POINTS = 500
21
+ _MAX_ANNOTATION_ENTRY_POINTS = 1000
22
22
 
23
23
  _REST_CONTROLLER_RE = re.compile(r'@RestController\b')
24
24
  _MVC_CONTROLLER_RE = re.compile(r'@Controller\b')
@@ -236,10 +236,12 @@ class JavaDetector(AbstractDetector):
236
236
  ]
237
237
 
238
238
  # 2. Annotation-based scan: @RestController, @WebFilter, FilterRegistrationBean
239
- scan_candidates = [
240
- p for p in all_java
241
- if "/test/" not in p and "/tests/" not in p
242
- ][:_MAX_JAVA_ENTRY_SCAN]
239
+ # Prioritize Controller-named files so all REST controllers are detected
240
+ # even in large codebases where total files > _MAX_JAVA_ENTRY_SCAN.
241
+ _non_test = [p for p in all_java if "/test/" not in p and "/tests/" not in p]
242
+ _ctrl_files = [p for p in _non_test if "Controller" in p]
243
+ _other_files = [p for p in _non_test if "Controller" not in p]
244
+ scan_candidates = _ctrl_files + _other_files[:max(0, _MAX_JAVA_ENTRY_SCAN - len(_ctrl_files))]
243
245
 
244
246
  annotation_eps: list[EntryPoint] = []
245
247
  for rel_path in scan_candidates:
@@ -1439,10 +1439,31 @@ def _serialize_contract_java(c: Any) -> dict[str, Any]:
1439
1439
  return item
1440
1440
 
1441
1441
 
1442
+ def _serialize_contract_mybatis_xml(c: Any) -> dict[str, Any]:
1443
+ """Serialize a MyBatis *Mapper.xml contract."""
1444
+ item: dict[str, Any] = {"path": c.path, "language": "mybatis-xml"}
1445
+ # Extract namespace stored as "namespace:<fqn>" in dependencies
1446
+ for dep in (c.dependencies or []):
1447
+ if dep.startswith("namespace:"):
1448
+ item["namespace"] = dep[len("namespace:"):]
1449
+ break
1450
+ exports_out: list[dict] = []
1451
+ for e in c.exports:
1452
+ entry: dict = {"kind": e.kind, "name": e.name}
1453
+ if getattr(e, "type_ref", None):
1454
+ entry["type"] = e.type_ref
1455
+ exports_out.append(entry)
1456
+ if exports_out:
1457
+ item["exports"] = exports_out
1458
+ return item
1459
+
1460
+
1442
1461
  def _serialize_contract_minimal(c: Any) -> dict[str, Any]:
1443
1462
  """Serialize one FileContract to minimal format."""
1444
1463
  if getattr(c, "language", None) == "java":
1445
1464
  return _serialize_contract_java(c)
1465
+ if getattr(c, "language", None) == "mybatis-xml":
1466
+ return _serialize_contract_mybatis_xml(c)
1446
1467
  item: dict[str, Any] = {"path": c.path, "role": c.role}
1447
1468
 
1448
1469
  if c.is_changed:
@@ -1560,6 +1581,11 @@ def _contract_view_standard(
1560
1581
  if contracts:
1561
1582
  serialized: list[dict[str, Any]] = []
1562
1583
  for c in contracts:
1584
+ if getattr(c, "language", None) == "mybatis-xml":
1585
+ item = _serialize_contract_mybatis_xml(c)
1586
+ item["relevance_score"] = round(c.relevance_score, 3)
1587
+ serialized.append(item)
1588
+ continue
1563
1589
  item: dict[str, Any] = {
1564
1590
  "path": c.path,
1565
1591
  "language": c.language,
@@ -1609,7 +1635,7 @@ def _contract_view_standard(
1609
1635
  item["ranking_reasons"] = non_trivial
1610
1636
  item["method"] = c.extraction_method
1611
1637
  serialized.append(item)
1612
- result["file_contracts"] = serialized
1638
+ result["contracts"] = serialized
1613
1639
 
1614
1640
  # Optional analysis sections (deep mode or when analyzers ran)
1615
1641
  if include_optional:
@@ -188,7 +188,7 @@ def test_cli_raw_mode_preserves_standard_output(tmp_path: Path) -> None:
188
188
  data = json.loads(result.output)
189
189
  assert "metadata" in data
190
190
  assert data["metadata"]["schema_version"] == "1.0"
191
- assert "file_contracts" not in data
191
+ assert "contracts" not in data
192
192
 
193
193
 
194
194
  def test_cli_max_symbols_flag(tmp_path: Path) -> None:
@@ -198,11 +198,11 @@ def test_cli_max_symbols_flag(tmp_path: Path) -> None:
198
198
  f"def func{i}a(): pass\ndef func{i}b(): pass\n"
199
199
  )
200
200
 
201
- # Use --mode standard to get file_contracts with full per-symbol detail
201
+ # Use --mode standard to get contracts with full per-symbol detail
202
202
  result = runner.invoke(app, ["--mode", "standard", "--max-symbols", "5", str(tmp_path)])
203
203
  assert result.exit_code == 0, result.output
204
204
  data = json.loads(result.output)
205
- contracts = data.get("file_contracts", [])
205
+ contracts = data.get("contracts", [])
206
206
  total = sum(
207
207
  len(c.get("exports", [])) + len(c.get("functions", [])) + len(c.get("types", []))
208
208
  for c in contracts
@@ -250,7 +250,7 @@ def test_cli_standard_mode_includes_detail_fields(tmp_path: Path) -> None:
250
250
  assert "schema_version" in data
251
251
  assert "stacks" in data
252
252
  assert "entry_points" in data
253
- assert "file_contracts" in data
253
+ assert "contracts" in data
254
254
 
255
255
 
256
256
  def test_cli_invalid_mode_exits_nonzero(tmp_path: Path) -> None:
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