sourcecode 1.30.20__tar.gz → 1.30.22__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 (195) hide show
  1. {sourcecode-1.30.20 → sourcecode-1.30.22}/PKG-INFO +3 -3
  2. {sourcecode-1.30.20 → sourcecode-1.30.22}/README.md +2 -2
  3. {sourcecode-1.30.20 → sourcecode-1.30.22}/pyproject.toml +1 -1
  4. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/cli.py +119 -8
  6. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/prepare_context.py +79 -51
  7. sourcecode-1.30.22/tests/test_output_ux.py +235 -0
  8. {sourcecode-1.30.20 → sourcecode-1.30.22}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  9. {sourcecode-1.30.20 → sourcecode-1.30.22}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  10. {sourcecode-1.30.20 → sourcecode-1.30.22}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  11. {sourcecode-1.30.20 → sourcecode-1.30.22}/.continue-here.md +0 -0
  12. {sourcecode-1.30.20 → sourcecode-1.30.22}/.github/workflows/build-windows.yml +0 -0
  13. {sourcecode-1.30.20 → sourcecode-1.30.22}/.gitignore +0 -0
  14. {sourcecode-1.30.20 → sourcecode-1.30.22}/.ruff.toml +0 -0
  15. {sourcecode-1.30.20 → sourcecode-1.30.22}/CONTRIBUTING.md +0 -0
  16. {sourcecode-1.30.20 → sourcecode-1.30.22}/LICENSE +0 -0
  17. {sourcecode-1.30.20 → sourcecode-1.30.22}/SECURITY.md +0 -0
  18. {sourcecode-1.30.20 → sourcecode-1.30.22}/docs/privacy.md +0 -0
  19. {sourcecode-1.30.20 → sourcecode-1.30.22}/docs/schema.md +0 -0
  20. {sourcecode-1.30.20 → sourcecode-1.30.22}/raw +0 -0
  21. {sourcecode-1.30.20 → sourcecode-1.30.22}/run_cli.py +0 -0
  22. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/adaptive_scanner.py +0 -0
  23. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/architecture_analyzer.py +0 -0
  24. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/architecture_summary.py +0 -0
  25. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/ast_extractor.py +0 -0
  26. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/classifier.py +0 -0
  27. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/code_notes_analyzer.py +0 -0
  28. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/confidence_analyzer.py +0 -0
  29. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/context_scorer.py +0 -0
  30. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/context_summarizer.py +0 -0
  31. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/contract_model.py +0 -0
  32. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/contract_pipeline.py +0 -0
  33. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/coverage_parser.py +0 -0
  34. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/dependency_analyzer.py +0 -0
  35. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/__init__.py +0 -0
  36. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/base.py +0 -0
  37. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/csproj_parser.py +0 -0
  38. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/dart.py +0 -0
  39. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/dotnet.py +0 -0
  40. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/elixir.py +0 -0
  41. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/go.py +0 -0
  42. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/heuristic.py +0 -0
  43. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/hybrid.py +0 -0
  44. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/java.py +0 -0
  45. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/jvm_ext.py +0 -0
  46. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/nodejs.py +0 -0
  47. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/parsers.py +0 -0
  48. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/php.py +0 -0
  49. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/project.py +0 -0
  50. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/python.py +0 -0
  51. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/ruby.py +0 -0
  52. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/rust.py +0 -0
  53. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/systems.py +0 -0
  54. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/terraform.py +0 -0
  55. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/detectors/tooling.py +0 -0
  56. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/doc_analyzer.py +0 -0
  57. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/entrypoint_classifier.py +0 -0
  58. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/env_analyzer.py +0 -0
  59. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/file_classifier.py +0 -0
  60. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/flow_analyzer.py +0 -0
  61. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/git_analyzer.py +0 -0
  62. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/graph_analyzer.py +0 -0
  63. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/metrics_analyzer.py +0 -0
  64. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/pr_comment_renderer.py +0 -0
  65. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/progress.py +0 -0
  66. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/ranking_engine.py +0 -0
  67. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/redactor.py +0 -0
  68. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/relevance_scorer.py +0 -0
  69. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/repo_classifier.py +0 -0
  70. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/repository_ir.py +0 -0
  71. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/runtime_classifier.py +0 -0
  72. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/scanner.py +0 -0
  73. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/schema.py +0 -0
  74. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/semantic_analyzer.py +0 -0
  75. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/serializer.py +0 -0
  76. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/summarizer.py +0 -0
  77. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/telemetry/__init__.py +0 -0
  78. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/telemetry/config.py +0 -0
  79. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/telemetry/consent.py +0 -0
  80. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/telemetry/events.py +0 -0
  81. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/telemetry/filters.py +0 -0
  82. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/telemetry/transport.py +0 -0
  83. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/tree_utils.py +0 -0
  84. {sourcecode-1.30.20 → sourcecode-1.30.22}/src/sourcecode/workspace.py +0 -0
  85. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/__init__.py +0 -0
  86. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/conftest.py +0 -0
  87. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/coverage.xml +0 -0
  88. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  89. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/fastapi_app/src/main.py +0 -0
  90. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  91. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/go_service/go.mod +0 -0
  92. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/jacoco.xml +0 -0
  93. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/latin1_sample.java +0 -0
  94. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/latin1_sample_iso.java +0 -0
  95. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/lcov.info +0 -0
  96. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  97. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/nextjs_app/package.json +0 -0
  98. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  99. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  100. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  101. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  102. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  103. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  104. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  105. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
  106. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
  107. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
  108. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
  109. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
  110. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
  111. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
  112. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
  113. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
  114. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
  115. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
  116. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
  117. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
  118. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
  119. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
  120. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  121. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
  122. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  123. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  124. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  125. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  126. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  127. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
  128. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  129. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  130. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
  131. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_architecture_analyzer.py +0 -0
  132. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_architecture_summary.py +0 -0
  133. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_ast_extractor.py +0 -0
  134. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_block1_reliability.py +0 -0
  135. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_block2_coverage.py +0 -0
  136. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_block5_quality.py +0 -0
  137. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_bug_fixes_v16.py +0 -0
  138. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_classifier.py +0 -0
  139. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_cli.py +0 -0
  140. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_code_notes_analyzer.py +0 -0
  141. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_context_scorer.py +0 -0
  142. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_contract_pipeline.py +0 -0
  143. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_coverage_parser.py +0 -0
  144. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_cross_consistency.py +0 -0
  145. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_dependency_analyzer_node_python.py +0 -0
  146. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_dependency_analyzer_polyglot.py +0 -0
  147. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_dependency_schema.py +0 -0
  148. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_dotnet.py +0 -0
  149. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_go_rust_java.py +0 -0
  150. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_nodejs.py +0 -0
  151. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_php_ruby_dart.py +0 -0
  152. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_python.py +0 -0
  153. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_universal_managed.py +0 -0
  154. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detector_universal_systems.py +0 -0
  155. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_detectors_base.py +0 -0
  156. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_doc_analyzer_jsdom.py +0 -0
  157. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_doc_analyzer_python.py +0 -0
  158. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_encoding_regression.py +0 -0
  159. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_graph_analyzer_polyglot.py +0 -0
  160. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_graph_analyzer_python_node.py +0 -0
  161. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_graph_schema.py +0 -0
  162. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_hybrid_inference.py +0 -0
  163. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration.py +0 -0
  164. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_dependencies.py +0 -0
  165. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_detection.py +0 -0
  166. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_docs.py +0 -0
  167. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_graph_modules.py +0 -0
  168. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_lqn.py +0 -0
  169. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_metrics.py +0 -0
  170. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_multistack.py +0 -0
  171. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_semantics.py +0 -0
  172. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_integration_universal.py +0 -0
  173. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_java_spring_integration.py +0 -0
  174. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_metrics_analyzer.py +0 -0
  175. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_packaging.py +0 -0
  176. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_phase1_improvements.py +0 -0
  177. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_pipeline_integrity.py +0 -0
  178. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_real_projects.py +0 -0
  179. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_redactor.py +0 -0
  180. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_repository_ir.py +0 -0
  181. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_scanner.py +0 -0
  182. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_schema.py +0 -0
  183. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_schema_normalization.py +0 -0
  184. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_semantic_analyzer_node.py +0 -0
  185. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_semantic_analyzer_python.py +0 -0
  186. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_semantic_import_resolution.py +0 -0
  187. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_semantic_schema.py +0 -0
  188. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_signal_hierarchy.py +0 -0
  189. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_summarizer.py +0 -0
  190. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_surface_honesty.py +0 -0
  191. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_task_differentiation.py +0 -0
  192. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_telemetry.py +0 -0
  193. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_v131_improvements.py +0 -0
  194. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_v1_10_regressions.py +0 -0
  195. {sourcecode-1.30.20 → sourcecode-1.30.22}/tests/test_workspace_analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.30.20
3
+ Version: 1.30.22
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
  **Deterministic, behavior-aware codebase context for AI agents and PR review.**
223
223
 
224
- ![Version](https://img.shields.io/badge/version-1.30.20-blue)
224
+ ![Version](https://img.shields.io/badge/version-1.30.22-blue)
225
225
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
226
226
 
227
227
  ---
@@ -257,7 +257,7 @@ pipx install sourcecode
257
257
 
258
258
  ```bash
259
259
  sourcecode version
260
- # sourcecode 1.30.20
260
+ # sourcecode 1.30.22
261
261
  ```
262
262
 
263
263
  ---
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Deterministic, behavior-aware codebase context for AI agents and PR review.**
4
4
 
5
- ![Version](https://img.shields.io/badge/version-1.30.20-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.30.22-blue)
6
6
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
7
7
 
8
8
  ---
@@ -38,7 +38,7 @@ pipx install sourcecode
38
38
 
39
39
  ```bash
40
40
  sourcecode version
41
- # sourcecode 1.30.20
41
+ # sourcecode 1.30.22
42
42
  ```
43
43
 
44
44
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.30.20"
7
+ version = "1.30.22"
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.30.20"
3
+ __version__ = "1.30.22"
@@ -1596,6 +1596,86 @@ def main(
1596
1596
  typer.echo("✓ copied to clipboard", err=True)
1597
1597
 
1598
1598
 
1599
+ # ── prepare-context output helpers ────────────────────────────────────────────
1600
+
1601
+ def _make_explanation(reason: str, why: str) -> str:
1602
+ """Merge reason+why into one human string. Drop internal pipe-format jargon."""
1603
+ if why and not why.startswith("artifact_type:"):
1604
+ return why
1605
+ return reason
1606
+
1607
+
1608
+ def _serialize_relevant_file(f: Any) -> dict:
1609
+ from dataclasses import asdict as _asdict
1610
+ d = {k: v for k, v in _asdict(f).items() if v != "" and v is not None}
1611
+ reason = d.pop("reason", "") or ""
1612
+ why = d.pop("why", "") or ""
1613
+ d.pop("score", None) # score removed from public output (internal ranking only)
1614
+ explanation = _make_explanation(reason, why)
1615
+ if explanation:
1616
+ d["explanation"] = explanation
1617
+ return d
1618
+
1619
+
1620
+ def _transform_impact_scores(scores: dict) -> dict:
1621
+ """Convert internal impact_score_per_file to human-readable review signals."""
1622
+ _THRESHOLDS = [(0.60, "high"), (0.40, "medium")]
1623
+ _CT_LABELS: dict[str, str] = {
1624
+ "security_change": "security-sensitive change",
1625
+ "behavioral_change": "behavioral change",
1626
+ "structural_change": "structural modification",
1627
+ "configuration_change": "configuration change",
1628
+ "dependency_change": "dependency update",
1629
+ "ui_change": "UI change",
1630
+ }
1631
+ result: dict = {}
1632
+ for path, entry in scores.items():
1633
+ raw = entry.get("_rank_score", 0.0)
1634
+ priority = next((p for thresh, p in _THRESHOLDS if raw >= thresh), "low")
1635
+ signals: list[str] = [
1636
+ _CT_LABELS[ct] for ct in entry.get("change_types", []) if ct in _CT_LABELS
1637
+ ]
1638
+ ev = entry.get("evidence", {})
1639
+ callers = ev.get("reverse_edge_count", 0)
1640
+ if callers:
1641
+ signals.append(f"imported by {callers} other file{'s' if callers > 1 else ''}")
1642
+ out_entry: dict = {"review_priority": priority}
1643
+ if signals:
1644
+ out_entry["signals"] = signals
1645
+ result[path] = out_entry
1646
+ return result
1647
+
1648
+
1649
+ def _clean_system_impact(si: dict) -> dict:
1650
+ """Remove empty lists/dicts from system_impact — only emit positive signals."""
1651
+ return {k: v for k, v in si.items() if v}
1652
+
1653
+
1654
+ def _build_human_summary(output: Any) -> dict:
1655
+ """Human-readable summary block for delta/review-pr output."""
1656
+ concerns: list[str] = []
1657
+ si = getattr(output, "system_impact", {}) or {}
1658
+ for ri in si.get("runtime_impact", []):
1659
+ sig = ri.get("signal", "")
1660
+ if sig:
1661
+ concerns.append(sig)
1662
+ for bc in si.get("behavioral_changes", []):
1663
+ stmt = bc.get("statement", "")
1664
+ if stmt:
1665
+ concerns.append(stmt)
1666
+ cov = getattr(output, "test_coverage_risk", {}) or {}
1667
+ missing = cov.get("changed_files_without_tests", [])
1668
+ if missing:
1669
+ concerns.append(f"{len(missing)} changed file(s) without test coverage detected")
1670
+ summary: dict = {}
1671
+ if getattr(output, "impact_summary", None):
1672
+ summary["description"] = output.impact_summary
1673
+ if concerns:
1674
+ summary["review_concerns"] = concerns[:6]
1675
+ summary["confidence"] = (getattr(output, "confidence", None) or "medium").upper()
1676
+ return summary
1677
+
1678
+
1599
1679
  @app.command("prepare-context")
1600
1680
  def prepare_context_cmd(
1601
1681
  task: Optional[str] = typer.Argument(
@@ -1801,9 +1881,14 @@ def prepare_context_cmd(
1801
1881
  def _task_include(field: str) -> bool:
1802
1882
  return _content_filter.get(field, True)
1803
1883
 
1884
+ _run_id = hashlib.sha256(
1885
+ f"{task}:{target}:{since or ''}:{format or ''}:{symptom or ''}".encode()
1886
+ ).hexdigest()[:16]
1887
+
1804
1888
  out: dict[str, Any] = {
1805
1889
  "task": output.task,
1806
1890
  "goal": output.goal,
1891
+ "run_id": _run_id,
1807
1892
  }
1808
1893
  if _task_include("project_summary"):
1809
1894
  out["project_summary"] = output.project_summary
@@ -1813,7 +1898,7 @@ def prepare_context_cmd(
1813
1898
  out["confidence"] = output.confidence
1814
1899
  if task != "review-pr" and _task_include("relevant_files"):
1815
1900
  out["relevant_files"] = [
1816
- {k: v for k, v in asdict(f).items() if v != ""}
1901
+ _serialize_relevant_file(f)
1817
1902
  for f in output.relevant_files
1818
1903
  ]
1819
1904
  if _task_include("key_dependencies") and output.key_dependencies:
@@ -1854,6 +1939,30 @@ def prepare_context_cmd(
1854
1939
  _sys.stdout.buffer.write(b"\n")
1855
1940
  _sys.stdout.buffer.flush()
1856
1941
  raise typer.Exit(code=1)
1942
+ if output.ci_decision == "no_changes":
1943
+ # Early exit: no diff — emit minimal JSON without any analysis fields.
1944
+ # Prevents no_changes from ever being serialized alongside relevant_files > 0.
1945
+ _nc_out: dict[str, Any] = {
1946
+ "task": output.task,
1947
+ "ci_decision": "no_changes",
1948
+ "summary": "No changes detected",
1949
+ }
1950
+ if output.since:
1951
+ _nc_out["since"] = output.since
1952
+ if output.analysis_scope:
1953
+ _nc_out["analysis_scope"] = output.analysis_scope
1954
+ _nc_json = json.dumps(_nc_out, indent=2, ensure_ascii=False)
1955
+ if output_path is not None:
1956
+ output_path.write_text(_nc_json, encoding="utf-8")
1957
+ else:
1958
+ import sys as _sys
1959
+ _sys.stdout.buffer.write(_nc_json.encode("utf-8"))
1960
+ _sys.stdout.buffer.write(b"\n")
1961
+ _sys.stdout.buffer.flush()
1962
+ if copy:
1963
+ _copy_to_clipboard(_nc_json)
1964
+ typer.echo("✓ copied to clipboard", err=True)
1965
+ raise typer.Exit()
1857
1966
  if output.ci_decision:
1858
1967
  out["ci_decision"] = output.ci_decision
1859
1968
  if output.since:
@@ -1864,16 +1973,19 @@ def prepare_context_cmd(
1864
1973
  out["affected_modules"] = output.affected_modules
1865
1974
  if output.risk_areas:
1866
1975
  out["risk_areas"] = output.risk_areas
1867
- if output.why_these_files:
1868
- out["reasoning"] = output.why_these_files
1869
1976
  if output.change_type:
1870
1977
  out["change_type"] = output.change_type
1871
1978
  if output.system_impact:
1872
- out["system_impact"] = output.system_impact
1979
+ _si = _clean_system_impact(output.system_impact)
1980
+ if _si:
1981
+ out["system_impact"] = _si
1873
1982
  if output.dependency_graph_summary:
1874
- out["dependency_graph_summary"] = output.dependency_graph_summary
1983
+ _dgraph = {k: v for k, v in output.dependency_graph_summary.items() if v is not None}
1984
+ if _dgraph:
1985
+ out["dependency_graph_summary"] = _dgraph
1875
1986
  if output.impact_score_per_file:
1876
- out["impact_score_per_file"] = output.impact_score_per_file
1987
+ out["impact_score_per_file"] = _transform_impact_scores(output.impact_score_per_file)
1988
+ out["summary"] = _build_human_summary(output)
1877
1989
  # review-pr specific fields
1878
1990
  if task == "review-pr":
1879
1991
  if output.error_code:
@@ -1928,8 +2040,7 @@ def prepare_context_cmd(
1928
2040
  out["behavioral_impact"] = output.behavioral_impact
1929
2041
  if output.impact_summary:
1930
2042
  out["impact_summary"] = output.impact_summary
1931
- if output.why_these_files:
1932
- out["reasoning"] = output.why_these_files
2043
+ out["summary"] = _build_human_summary(output)
1933
2044
  # git-first scope metadata
1934
2045
  out["scope"] = {
1935
2046
  "source": output.scope_source or "git_diff",
@@ -377,6 +377,25 @@ class TaskOutput:
377
377
  analysis_scope: dict = field(default_factory=dict)
378
378
 
379
379
 
380
+ @dataclass
381
+ class CanonicalAnalysisIR:
382
+ """Shared intermediate representation produced by _build_delta_impact.
383
+
384
+ Both delta and review-pr derive their task-specific output from this IR.
385
+ Never recalculate logic per command — render views from this single object.
386
+ """
387
+ relevant_files: list[RelevantFile]
388
+ impact_summary: str
389
+ affected_modules: list[str]
390
+ risk_areas: list[dict]
391
+ why_these_files: dict[str, str]
392
+ analysis_gaps: list[str]
393
+ system_impact: dict
394
+ change_type: list[str]
395
+ dependency_graph_summary: dict
396
+ impact_score_per_file: dict
397
+
398
+
380
399
  # ─────────────────────────────────────────────────────────────────────────────
381
400
  # Builder
382
401
  # ─────────────────────────────────────────────────────────────────────────────
@@ -556,7 +575,7 @@ _ARTIFACT_CHANGE_EFFECT: dict[str, str] = {
556
575
  "test": "test file (no production code modified)",
557
576
  "documentation": "documentation file (no runtime impact)",
558
577
  "ide_noise": "IDE/tooling artifact (no application impact)",
559
- "source": "application source (artifact role requires annotation inspection)",
578
+ "source": "application source file (role could not be confirmed from code signals)",
560
579
  }
561
580
 
562
581
  # Maps frontend symptom keywords → backend terms likely to contain the root cause.
@@ -934,7 +953,8 @@ class TaskContextBuilder:
934
953
  test_set = {p for p in all_paths if self._is_test(p)}
935
954
  source_set = {p for p in all_paths if not self._is_test(p) and self._is_source(p)}
936
955
 
937
- # Delta uses a dedicated impact-analysis path never the generic ranker.
956
+ # Delta and review-pr share CanonicalAnalysisIRcomputed once, rendered per task.
957
+ _ir: Optional[CanonicalAnalysisIR] = None
938
958
  _delta_impact_summary: Optional[str] = None
939
959
  _delta_affected_modules: list[str] = []
940
960
  _delta_risk_areas: list[dict] = []
@@ -947,23 +967,22 @@ class TaskContextBuilder:
947
967
 
948
968
  if task_name in ("delta", "review-pr"):
949
969
  _delta_changed_list: list[str] = sorted(_delta_files) if _delta_files else []
950
- (
951
- relevant_files,
952
- _delta_impact_summary,
953
- _delta_affected_modules,
954
- _delta_risk_areas,
955
- _delta_why,
956
- _delta_analysis_gaps,
957
- _delta_system_impact,
958
- _delta_change_type,
959
- _delta_dep_graph_summary,
960
- _delta_impact_score_per_file,
961
- ) = self._build_delta_impact(
970
+ _ir = self._build_delta_impact(
962
971
  changed_files=_delta_changed_list,
963
972
  all_paths=all_paths,
964
973
  entry_points=entry_points,
965
974
  since=since,
966
975
  )
976
+ relevant_files = _ir.relevant_files
977
+ _delta_impact_summary = _ir.impact_summary
978
+ _delta_affected_modules = _ir.affected_modules
979
+ _delta_risk_areas = _ir.risk_areas
980
+ _delta_why = _ir.why_these_files
981
+ _delta_analysis_gaps = _ir.analysis_gaps
982
+ _delta_system_impact = _ir.system_impact
983
+ _delta_change_type = _ir.change_type
984
+ _delta_dep_graph_summary = _ir.dependency_graph_summary
985
+ _delta_impact_score_per_file = _ir.impact_score_per_file
967
986
  else:
968
987
  relevant_files = self._rank_files(
969
988
  task_name, spec, all_paths, entry_set, test_set,
@@ -1156,22 +1175,24 @@ class TaskContextBuilder:
1156
1175
  else "unknown"
1157
1176
  )
1158
1177
  _impact_entry = _delta_impact_score_per_file.get(_f) or {}
1159
- _entry = {
1178
+ _ev_complete = {k: v for k, v in _impact_entry.get("evidence", {}).items() if v}
1179
+ _entry: dict = {
1160
1180
  "path": _f,
1161
1181
  "diff_source": _diff_source,
1162
1182
  "role": _role_obj,
1163
1183
  "artifact_type": _f_atype,
1164
1184
  "evidence": _evidence,
1165
1185
  "change_effect": {
1166
- "statement": _ARTIFACT_CHANGE_EFFECT.get(_f_atype, "application source (artifact role requires annotation inspection)"),
1186
+ "statement": _ARTIFACT_CHANGE_EFFECT.get(_f_atype, "application source file (role could not be confirmed)"),
1167
1187
  "classification_method": _f_cls.get("confidence", "low"),
1168
1188
  "epistemic_level": (
1169
1189
  "STRUCTURAL SIGNAL" if _f_cls.get("confidence", "low") == "high"
1170
1190
  else "INFERRED (LOW CONFIDENCE)"
1171
1191
  ),
1172
1192
  },
1173
- "evidence_completeness": _impact_entry.get("evidence", {}),
1174
1193
  }
1194
+ if _ev_complete:
1195
+ _entry["evidence_completeness"] = _ev_complete
1175
1196
  _pr_runtime_changes.append(_entry)
1176
1197
  # Split committed vs uncommitted — never merged
1177
1198
  if _f in _committed_set:
@@ -2295,13 +2316,10 @@ class TaskContextBuilder:
2295
2316
  all_paths: list[str],
2296
2317
  entry_points: list,
2297
2318
  since: Optional[str],
2298
- ) -> tuple[list[RelevantFile], str, list[str], list[dict[str, Any]], dict[str, str], list[str]]:
2319
+ ) -> "CanonicalAnalysisIR":
2299
2320
  """Build incremental impact analysis for changed files.
2300
2321
 
2301
- Returns:
2302
- (relevant_files, impact_summary, affected_modules, risk_areas,
2303
- why_these_files, analysis_gaps)
2304
-
2322
+ Returns CanonicalAnalysisIR — the shared IR consumed by delta and review-pr views.
2305
2323
  Changed files are always included in relevant_files (never dropped by score).
2306
2324
  Related files are expanded type-aware: controller→service→repository→mapper chain.
2307
2325
  Scoring is hierarchical by artifact_type, not by heuristic impact_level.
@@ -2469,6 +2487,18 @@ class TaskContextBuilder:
2469
2487
  return "data_access"
2470
2488
  if atype == "service":
2471
2489
  return "service" # annotation-confirmed — not "core_service" (overclaim)
2490
+ # Name-pattern heuristics — only when atype alone gave no verdict.
2491
+ # These are INFERRED (LOW CONFIDENCE) — stem match, not annotation evidence.
2492
+ if any(kw in stem_lower for kw in ("validator", "validation")):
2493
+ return "validation_component"
2494
+ if any(kw in stem_lower for kw in ("controller", "resource", "endpoint", "rest")):
2495
+ return "external_interface"
2496
+ if any(kw in stem_lower for kw in ("service", "svc", "usecase", "facade")):
2497
+ return "service"
2498
+ if any(kw in stem_lower for kw in ("repository", "repo", "dao", "store")):
2499
+ return "data_access"
2500
+ if any(kw in stem_lower for kw in ("config", "configuration", "settings", "properties")):
2501
+ return "configuration"
2472
2502
  return "unclassified" # no role claim without evidence
2473
2503
 
2474
2504
  def _structured_why(path: str, atype: str, module: str, role: str, risk_areas: list[str], cls_confidence: str = "low") -> str:
@@ -2489,17 +2519,17 @@ class TaskContextBuilder:
2489
2519
  return " | ".join(parts)
2490
2520
 
2491
2521
  if not changed_files:
2492
- return (
2493
- [],
2494
- "No changes detected — verify the git ref passed to --since",
2495
- [],
2496
- [],
2497
- {},
2498
- ["No changed files found. Check that --since ref exists and the diff is non-empty."],
2499
- {}, # system_impact
2500
- [], # change_type
2501
- {"edges": [], "propagation_depth": 0}, # dependency_graph_summary
2502
- {}, # impact_score_per_file
2522
+ return CanonicalAnalysisIR(
2523
+ relevant_files=[],
2524
+ impact_summary="No changes detected — verify the git ref passed to --since",
2525
+ affected_modules=[],
2526
+ risk_areas=[],
2527
+ why_these_files={},
2528
+ analysis_gaps=["No changed files found. Check that --since ref exists and the diff is non-empty."],
2529
+ system_impact={},
2530
+ change_type=[],
2531
+ dependency_graph_summary={"edges": [], "propagation_depth": 0},
2532
+ impact_score_per_file={},
2503
2533
  )
2504
2534
 
2505
2535
  ep_paths = {ep.path for ep in entry_points}
@@ -2992,12 +3022,12 @@ class TaskContextBuilder:
2992
3022
 
2993
3023
  # ── Step 6: analysis gaps ──────────────────────────────────────────────
2994
3024
  _bfs_note = (
2995
- f"BFS multi-hop import propagation repo-wide (propagation_depth={_max_hop})"
3025
+ f"multi-hop import tracing performed (depth {_max_hop})"
2996
3026
  if _max_hop >= 1
2997
- else "no import-link propagation (no scannable changed files)"
3027
+ else "no downstream dependencies could be verified"
2998
3028
  )
2999
3029
  analysis_gaps: list[str] = [
3000
- f"Related file expansion: type-aware chain expansion + {_bfs_note} + module/directory heuristics",
3030
+ f"Related file expansion via import analysis and directory proximity ({_bfs_note})",
3001
3031
  ]
3002
3032
  if _expansion_truncated:
3003
3033
  analysis_gaps.insert(0,
@@ -3015,10 +3045,8 @@ class TaskContextBuilder:
3015
3045
  low_confidence = [f for f, cls in classifications.items() if cls.get("confidence") == "low" and not cls["is_noise"]]
3016
3046
  if low_confidence:
3017
3047
  analysis_gaps.append(
3018
- f"{len(low_confidence)} file(s) classified with low confidence"
3019
- " (artifact type inferred from extension only)"
3020
- " — consider adding stem patterns to _classify_changed_file: "
3021
- + ", ".join(Path(f).name for f in low_confidence[:3])
3048
+ f"{len(low_confidence)} file(s) role inferred from filename only"
3049
+ f" (no code signal found): {', '.join(Path(f).name for f in low_confidence[:3])}"
3022
3050
  )
3023
3051
  if not affected_modules_set and any(not cls["is_noise"] for cls in classifications.values()):
3024
3052
  analysis_gaps.append(
@@ -3026,17 +3054,17 @@ class TaskContextBuilder:
3026
3054
  " — related file expansion uses directory proximity only"
3027
3055
  )
3028
3056
 
3029
- return (
3030
- relevant,
3031
- impact_summary,
3032
- sorted(affected_modules_set),
3033
- risk_areas_out,
3034
- why,
3035
- analysis_gaps,
3036
- system_impact,
3037
- aggregate_change_type,
3038
- dependency_graph_summary,
3039
- impact_score_per_file,
3057
+ return CanonicalAnalysisIR(
3058
+ relevant_files=relevant,
3059
+ impact_summary=impact_summary,
3060
+ affected_modules=sorted(affected_modules_set),
3061
+ risk_areas=risk_areas_out,
3062
+ why_these_files=why,
3063
+ analysis_gaps=analysis_gaps,
3064
+ system_impact=system_impact,
3065
+ change_type=aggregate_change_type,
3066
+ dependency_graph_summary=dependency_graph_summary,
3067
+ impact_score_per_file=impact_score_per_file,
3040
3068
  )
3041
3069
 
3042
3070
  def _resolve_git_baseline(self, since: Optional[str]) -> dict[str, Any]: