sourcecode 1.32.0__tar.gz → 1.32.2__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 (237) hide show
  1. sourcecode-1.32.2/.continue-here.md +106 -0
  2. {sourcecode-1.32.0 → sourcecode-1.32.2}/PKG-INFO +1 -1
  3. {sourcecode-1.32.0 → sourcecode-1.32.2}/pyproject.toml +1 -1
  4. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/architecture_analyzer.py +64 -15
  6. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/classifier.py +4 -0
  7. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/cli.py +58 -3
  8. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/context_summarizer.py +1 -0
  9. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/dependency_analyzer.py +3 -3
  10. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/java.py +6 -1
  11. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/server.py +36 -0
  12. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/prepare_context.py +7 -1
  13. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/repository_ir.py +6 -1
  14. sourcecode-1.32.2/src/sourcecode/ris.py +372 -0
  15. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/summarizer.py +1 -0
  16. sourcecode-1.32.0/.continue-here.md +0 -89
  17. {sourcecode-1.32.0 → sourcecode-1.32.2}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  18. {sourcecode-1.32.0 → sourcecode-1.32.2}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  19. {sourcecode-1.32.0 → sourcecode-1.32.2}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  20. {sourcecode-1.32.0 → sourcecode-1.32.2}/.github/workflows/build-windows.yml +0 -0
  21. {sourcecode-1.32.0 → sourcecode-1.32.2}/.gitignore +0 -0
  22. {sourcecode-1.32.0 → sourcecode-1.32.2}/.ruff.toml +0 -0
  23. {sourcecode-1.32.0 → sourcecode-1.32.2}/.sourcecode-cache/snapshot-3b5997a-fa5c742c.json +0 -0
  24. {sourcecode-1.32.0 → sourcecode-1.32.2}/AUDIT_REAL_REPOS.md +0 -0
  25. {sourcecode-1.32.0 → sourcecode-1.32.2}/AUDIT_v1.31.23.md +0 -0
  26. {sourcecode-1.32.0 → sourcecode-1.32.2}/CHANGELOG.md +0 -0
  27. {sourcecode-1.32.0 → sourcecode-1.32.2}/CONTRIBUTING.md +0 -0
  28. {sourcecode-1.32.0 → sourcecode-1.32.2}/LICENSE +0 -0
  29. {sourcecode-1.32.0 → sourcecode-1.32.2}/README.md +0 -0
  30. {sourcecode-1.32.0 → sourcecode-1.32.2}/SECURITY.md +0 -0
  31. {sourcecode-1.32.0 → sourcecode-1.32.2}/docs/PRODUCT_AUDIT.md +0 -0
  32. {sourcecode-1.32.0 → sourcecode-1.32.2}/docs/PRODUCT_TIERS.md +0 -0
  33. {sourcecode-1.32.0 → sourcecode-1.32.2}/docs/USER_GUIDE.md +0 -0
  34. {sourcecode-1.32.0 → sourcecode-1.32.2}/docs/privacy.md +0 -0
  35. {sourcecode-1.32.0 → sourcecode-1.32.2}/docs/schema.md +0 -0
  36. {sourcecode-1.32.0 → sourcecode-1.32.2}/raw +0 -0
  37. {sourcecode-1.32.0 → sourcecode-1.32.2}/run_cli.py +0 -0
  38. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/adaptive_scanner.py +0 -0
  39. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/architecture_summary.py +0 -0
  40. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/ast_extractor.py +0 -0
  41. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/cache.py +0 -0
  42. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/canonical_ir.py +0 -0
  43. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/code_notes_analyzer.py +0 -0
  44. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/confidence_analyzer.py +0 -0
  45. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/context_scorer.py +0 -0
  46. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/contract_model.py +0 -0
  47. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/contract_pipeline.py +0 -0
  48. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/coverage_parser.py +0 -0
  49. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/__init__.py +0 -0
  50. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/base.py +0 -0
  51. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/csproj_parser.py +0 -0
  52. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/dart.py +0 -0
  53. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/dotnet.py +0 -0
  54. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/elixir.py +0 -0
  55. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/go.py +0 -0
  56. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/heuristic.py +0 -0
  57. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/hybrid.py +0 -0
  58. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/jvm_ext.py +0 -0
  59. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/nodejs.py +0 -0
  60. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/parsers.py +0 -0
  61. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/php.py +0 -0
  62. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/project.py +0 -0
  63. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/python.py +0 -0
  64. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/ruby.py +0 -0
  65. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/rust.py +0 -0
  66. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/systems.py +0 -0
  67. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/terraform.py +0 -0
  68. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/detectors/tooling.py +0 -0
  69. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/doc_analyzer.py +0 -0
  70. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/entrypoint_classifier.py +0 -0
  71. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/env_analyzer.py +0 -0
  72. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/file_classifier.py +0 -0
  73. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/flow_analyzer.py +0 -0
  74. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/git_analyzer.py +0 -0
  75. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/graph_analyzer.py +0 -0
  76. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/license.py +0 -0
  77. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/__init__.py +0 -0
  78. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  79. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  80. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  81. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  82. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  83. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp/runner.py +0 -0
  84. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/mcp_nudge.py +0 -0
  85. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/metrics_analyzer.py +0 -0
  86. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/output_budget.py +0 -0
  87. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/path_filters.py +0 -0
  88. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/pr_comment_renderer.py +0 -0
  89. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/progress.py +0 -0
  90. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/ranking_engine.py +0 -0
  91. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/redactor.py +0 -0
  92. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/relevance_scorer.py +0 -0
  93. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/repo_classifier.py +0 -0
  94. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/runtime_classifier.py +0 -0
  95. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/scanner.py +0 -0
  96. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/schema.py +0 -0
  97. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/semantic_analyzer.py +0 -0
  98. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/serializer.py +0 -0
  99. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/telemetry/__init__.py +0 -0
  100. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/telemetry/config.py +0 -0
  101. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/telemetry/consent.py +0 -0
  102. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/telemetry/events.py +0 -0
  103. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/telemetry/filters.py +0 -0
  104. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/telemetry/transport.py +0 -0
  105. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/tree_utils.py +0 -0
  106. {sourcecode-1.32.0 → sourcecode-1.32.2}/src/sourcecode/workspace.py +0 -0
  107. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/__init__.py +0 -0
  108. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/conftest.py +0 -0
  109. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/coverage.xml +0 -0
  110. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  111. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/fastapi_app/src/main.py +0 -0
  112. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  113. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/go_service/go.mod +0 -0
  114. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/jacoco.xml +0 -0
  115. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/latin1_sample.java +0 -0
  116. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/latin1_sample_iso.java +0 -0
  117. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/lcov.info +0 -0
  118. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  119. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/nextjs_app/package.json +0 -0
  120. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  121. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  122. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  123. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  124. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  125. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  126. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  127. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
  128. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
  129. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
  130. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
  131. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
  132. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
  133. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
  134. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
  135. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
  136. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
  137. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
  138. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
  139. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
  140. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
  141. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
  142. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  143. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
  144. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  145. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  146. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  147. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  148. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  149. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
  150. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  151. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  152. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
  153. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_architecture_analyzer.py +0 -0
  154. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_architecture_summary.py +0 -0
  155. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_ast_extractor.py +0 -0
  156. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_audit_fixes.py +0 -0
  157. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_audit_sas_v2.py +0 -0
  158. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_block1_reliability.py +0 -0
  159. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_block2_coverage.py +0 -0
  160. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_block5_quality.py +0 -0
  161. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_broadleaf_fixes.py +0 -0
  162. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v1302.py +0 -0
  163. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v13115.py +0 -0
  164. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v1312.py +0 -0
  165. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v13122.py +0 -0
  166. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v1313.py +0 -0
  167. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v13130.py +0 -0
  168. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v1321.py +0 -0
  169. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v16.py +0 -0
  170. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_bug_fixes_v2.py +0 -0
  171. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_cache.py +0 -0
  172. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_canonical_ir.py +0 -0
  173. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_classifier.py +0 -0
  174. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_cli.py +0 -0
  175. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_code_notes_analyzer.py +0 -0
  176. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_context_scorer.py +0 -0
  177. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_contract_pipeline.py +0 -0
  178. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_coverage_parser.py +0 -0
  179. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_cross_consistency.py +0 -0
  180. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_dependency_analyzer_node_python.py +0 -0
  181. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_dependency_analyzer_polyglot.py +0 -0
  182. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_dependency_schema.py +0 -0
  183. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_dotnet.py +0 -0
  184. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_go_rust_java.py +0 -0
  185. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_nodejs.py +0 -0
  186. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_php_ruby_dart.py +0 -0
  187. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_python.py +0 -0
  188. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_universal_managed.py +0 -0
  189. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detector_universal_systems.py +0 -0
  190. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_detectors_base.py +0 -0
  191. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_doc_analyzer_jsdom.py +0 -0
  192. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_doc_analyzer_python.py +0 -0
  193. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_encoding_regression.py +0 -0
  194. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_enterprise_benchmarks.py +0 -0
  195. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_graph_analyzer_polyglot.py +0 -0
  196. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_graph_analyzer_python_node.py +0 -0
  197. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_graph_schema.py +0 -0
  198. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_hybrid_inference.py +0 -0
  199. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration.py +0 -0
  200. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_dependencies.py +0 -0
  201. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_detection.py +0 -0
  202. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_docs.py +0 -0
  203. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_graph_modules.py +0 -0
  204. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_lqn.py +0 -0
  205. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_metrics.py +0 -0
  206. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_multistack.py +0 -0
  207. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_semantics.py +0 -0
  208. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_integration_universal.py +0 -0
  209. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_java_spring_integration.py +0 -0
  210. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_mcp_nudge.py +0 -0
  211. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_mcp_runner.py +0 -0
  212. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_mcp_serve.py +0 -0
  213. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_mcp_tools.py +0 -0
  214. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_metrics_analyzer.py +0 -0
  215. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_output_ux.py +0 -0
  216. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_packaging.py +0 -0
  217. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_phase1_improvements.py +0 -0
  218. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_pipeline_integrity.py +0 -0
  219. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_real_projects.py +0 -0
  220. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_redactor.py +0 -0
  221. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_repository_ir.py +0 -0
  222. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_scanner.py +0 -0
  223. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_schema.py +0 -0
  224. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_schema_normalization.py +0 -0
  225. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_scoring_calibration.py +0 -0
  226. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_semantic_analyzer_node.py +0 -0
  227. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_semantic_analyzer_python.py +0 -0
  228. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_semantic_import_resolution.py +0 -0
  229. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_semantic_schema.py +0 -0
  230. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_signal_hierarchy.py +0 -0
  231. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_summarizer.py +0 -0
  232. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_surface_honesty.py +0 -0
  233. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_task_differentiation.py +0 -0
  234. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_telemetry.py +0 -0
  235. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_v131_improvements.py +0 -0
  236. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_v1_10_regressions.py +0 -0
  237. {sourcecode-1.32.0 → sourcecode-1.32.2}/tests/test_workspace_analyzer.py +0 -0
@@ -0,0 +1,106 @@
1
+ # .continue-here.md — sourcecode CLI
2
+ **Session paused:** 2026-05-28
3
+ **Branch:** master
4
+ **Last commit:** `7b5011e` fix: 9 correctness bugs — i18n, controller detection, project_type, dep dedup, arch pattern
5
+ **Version:** 1.32.1
6
+
7
+ ---
8
+
9
+ ## What was done this session
10
+
11
+ Fixed 9 correctness/reliability bugs identified by user from testing against spring-petclinic and other Spring repos. All committed in `7b5011e`.
12
+
13
+ | # | Severity | File(s) | Fix |
14
+ |---|----------|---------|-----|
15
+ | 1 | CRITICAL | `architecture_analyzer.py`, `dependency_analyzer.py`, `cli.py` | 6 Spanish strings in JSON output → English |
16
+ | 2 | HIGH | `detectors/java.py` | `@Controller` detection accepts `@GetMapping`/`@PostMapping`/etc, not just `@RequestMapping` — fixes undercount of controllers |
17
+ | 3 | HIGH | `detectors/java.py`, `classifier.py`, `context_summarizer.py`, `summarizer.py` | Added Thymeleaf/FreeMarker detection; classifier returns `"web_mvc"` for Spring + server-side template apps instead of `"api"` |
18
+ | 4 | MEDIUM | `prepare_context.py` | Dedup `key_dependencies` by name before ranking — mirrors dedup already in cli.py |
19
+ | 5 | MEDIUM | `architecture_analyzer.py` | New `_detect_spring_domain_modules()` — detects petclinic-style domain packages via longest-common-prefix stripping; returns `"spring_mvc_layered"` pattern |
20
+ | 6 | MEDIUM | — | Resolved by Bug #2 (IR controller count now consistent with entry_points) |
21
+ | 7 | LOW | `repository_ir.py` | `_canonical_subsystem_pkg` uses depth 5 for `springframework`/`apache` namespaces so `cross_module_impact.module` shows app modules not framework package names |
22
+ | 8 | LOW | `repository_ir.py` | `mappers_affected.role` defaults to `"repository"` for JPA repos, `"mapper"` only for MyBatis `mapper_interface` symbols |
23
+ | 9 | LOW | — | **SKIPPED** — onboard vs architecture confidence divergence; no acceptance criterion check; low risk |
24
+
25
+ Version also bumped: 1.32.0 → 1.32.1 (`__init__.py` + `pyproject.toml`).
26
+
27
+ ---
28
+
29
+ ## What remains
30
+
31
+ ### From the bug fix task spec
32
+ - [ ] **Bug #9** (LOW): `onboard.confidence "high"` vs `architecture.confidence "low"` divergence — use min of two, or document. Not in acceptance criteria so deferred.
33
+ - [ ] **Validation**: Run `sourcecode spring-petclinic --agent | jq .` to verify acceptance criteria live:
34
+ - JSON output 100% English (done statically via grep — passed)
35
+ - `entry_points.controllers.classes == 6`
36
+ - `project_type: "web_mvc"`
37
+ - `key_dependencies` no duplicates
38
+ - `architecture.pattern: "spring_mvc_layered"`
39
+
40
+ ### From session 29 handoff (pre-existing)
41
+ Three tiering policy gaps — still open:
42
+ - **GAP 1 (easy)**: Add `"upgrade_hint": "sourcecode activate <license_key>"` to JSON payload in `require_feature()` in `license.py:244` — one-liner
43
+ - **GAP 2 (medium)**: Tiered `--help` output (Free shows core commands + lock labels, Pro shows full). Requires custom `--help` callback since `is_pro` unavailable at module init.
44
+ - **GAP 3 (medium)**: Free-tier node cap (max 10) for `--graph-modules` and `--semantics` outputs
45
+
46
+ ### Optional P1 (backlog)
47
+ - `project_summary` quality improvements
48
+ - `relevant_files.score` ranking improvements
49
+
50
+ ---
51
+
52
+ ## Key technical context for next session
53
+
54
+ ### Bug #5 — spring domain detection
55
+ `_detect_spring_domain_modules` in `architecture_analyzer.py`:
56
+ 1. Finds longest common path prefix across all source paths
57
+ 2. Strips it (e.g. `src/main/java/org/springframework/samples/petclinic/`)
58
+ 3. Takes first remaining segment as module name
59
+ 4. ≥3 distinct modules with ≥2 files each → returns `"spring_mvc_layered"`
60
+ Pattern priority 3 in `_PATTERN_PRIORITY` (same as `"mvc"`).
61
+
62
+ ### Bug #3 classifier ordering
63
+ `classifier.py._classify_project_type()` order:
64
+ 1. `_WEB_FRAMEWORKS` → `"webapp"`
65
+ 2. NEW: `_SERVERSIDE_TEMPLATE_FRAMEWORKS` (Thymeleaf, FreeMarker) → `"web_mvc"`
66
+ 3. `_API_FRAMEWORKS` (Spring Boot, etc.) → `"api"`
67
+
68
+ ### Bug #7 — framework namespace depth
69
+ Only triggers when `parts[1] in _FRAMEWORK_NS` AND `len(parts) >= 5`.
70
+ `org.keycloak.services.Foo` → parts[1]="keycloak" (not in FRAMEWORK_NS) → unchanged.
71
+ `org.springframework.samples.petclinic.owner.X` → depth 5 → `org.springframework.samples.petclinic.owner`.
72
+
73
+ ### GAP 1 location (license.py:244)
74
+ ```python
75
+ payload = {
76
+ "error": "pro_required",
77
+ "feature": feature_name,
78
+ "message": (...),
79
+ # ADD: "upgrade_hint": "sourcecode activate <license_key>",
80
+ }
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Files modified this session
86
+ - `src/sourcecode/__init__.py`
87
+ - `pyproject.toml`
88
+ - `src/sourcecode/architecture_analyzer.py`
89
+ - `src/sourcecode/classifier.py`
90
+ - `src/sourcecode/cli.py`
91
+ - `src/sourcecode/context_summarizer.py`
92
+ - `src/sourcecode/dependency_analyzer.py`
93
+ - `src/sourcecode/detectors/java.py`
94
+ - `src/sourcecode/prepare_context.py`
95
+ - `src/sourcecode/repository_ir.py`
96
+ - `src/sourcecode/summarizer.py`
97
+
98
+ ## Untracked (not part of current work)
99
+ - `docs/PRODUCT_AUDIT.md`
100
+
101
+ ---
102
+
103
+ ## Resume
104
+ ```
105
+ /gsd:resume-work
106
+ ```
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.32.0
3
+ Version: 1.32.2
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.32.0"
7
+ version = "1.32.2"
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.32.0"
3
+ __version__ = "1.32.2"
@@ -152,14 +152,15 @@ LAYER_PATTERNS: dict[str, dict[str, list[str]]] = {
152
152
 
153
153
  # Higher value = wins when score ties
154
154
  _PATTERN_PRIORITY: dict[str, int] = {
155
- "cqrs": 8,
156
- "clean": 7,
157
- "onion": 6,
158
- "hexagonal": 5,
159
- "monorepo": 4,
160
- "mvc": 3,
161
- "layered": 2,
162
- "fullstack": 1,
155
+ "cqrs": 8,
156
+ "clean": 7,
157
+ "onion": 6,
158
+ "hexagonal": 5,
159
+ "monorepo": 4,
160
+ "spring_mvc_layered": 3,
161
+ "mvc": 3,
162
+ "layered": 2,
163
+ "fullstack": 1,
163
164
  }
164
165
 
165
166
 
@@ -248,9 +249,9 @@ class ArchitectureAnalyzer:
248
249
  pattern, layers = self._detect_layers(filtered)
249
250
  if pattern in (None, "flat", "unknown"):
250
251
  if pattern == "flat":
251
- limitations.append("Patron de capas no detectado: proyecto con estructura plana")
252
+ limitations.append("Layer pattern not detected: project has a flat directory structure")
252
253
  elif pattern == "unknown":
253
- limitations.append("Patron de capas no reconocido: estructura de directorios sin senales claras")
254
+ limitations.append("Unrecognized layer pattern: directory structure has no clear architectural signals")
254
255
 
255
256
  # Step 3b: monorepo override — workspace config is hard evidence.
256
257
  # Overrides all weak inferred patterns; only truly specialised patterns
@@ -269,7 +270,7 @@ class ArchitectureAnalyzer:
269
270
  pattern = "monorepo"
270
271
  layers = mono_layers
271
272
  limitations.append(
272
- "Workspace config detectadoarquitectura refleja topologia de paquetes"
273
+ "Workspace config detectedarchitecture reflects package topology"
273
274
  )
274
275
  ws_files = [p for p in sm.file_paths if p.split("/")[-1] in _WORKSPACE_CONFIG_FILES]
275
276
  evidence.append({
@@ -570,28 +571,76 @@ class ArchitectureAnalyzer:
570
571
  ))
571
572
  return best_pattern, layers
572
573
 
573
- # 2. Microservices structural detection (before file-naming heuristics)
574
+ # 2. Spring domain-module detection (petclinic-style: deep common prefix + feature dirs)
575
+ spring_result = self._detect_spring_domain_modules(source_paths)
576
+ if spring_result is not None:
577
+ return spring_result
578
+
579
+ # 3. Microservices structural detection (before file-naming heuristics)
574
580
  microservices_result = self._detect_microservices(source_paths)
575
581
  if microservices_result is not None:
576
582
  return microservices_result
577
583
 
578
- # 3. Functional file-naming heuristic: *_analyzer.py, cli.py, schema.py, …
584
+ # 5. Functional file-naming heuristic: *_analyzer.py, cli.py, schema.py, …
579
585
  func_result = self._detect_layered_functional(source_paths)
580
586
  if func_result is not None:
581
587
  return func_result
582
588
 
583
- # 4. Modular sub-package heuristic: ≥2 distinct named sub-packages
589
+ # 6. Modular sub-package heuristic: ≥2 distinct named sub-packages
584
590
  modular_result = self._detect_modular(source_paths)
585
591
  if modular_result is not None:
586
592
  return modular_result
587
593
 
588
- # 5. Fallback: flat (shallow) vs truly unknown (deep but unrecognised)
594
+ # 7. Fallback: flat (shallow) vs truly unknown (deep but unrecognised)
589
595
  max_depth = max(
590
596
  (len(p.replace("\\", "/").split("/")) - 1 for p in source_paths),
591
597
  default=0,
592
598
  )
593
599
  return ("flat" if max_depth <= 2 else "unknown"), []
594
600
 
601
+ def _detect_spring_domain_modules(
602
+ self, paths: list[str]
603
+ ) -> Optional[tuple[str, list[ArchitectureLayer]]]:
604
+ """Detect Spring Boot domain-organized packages (petclinic-style).
605
+
606
+ When all source paths share a deep common package prefix
607
+ (e.g. src/main/java/org/springframework/samples/petclinic/),
608
+ strips that prefix and detects feature/domain modules in the remainder.
609
+ Requires ≥3 distinct domain directories to avoid false positives.
610
+ """
611
+ if len(paths) < 6:
612
+ return None
613
+
614
+ parts_list = [p.replace("\\", "/").split("/") for p in paths]
615
+ min_depth = min(len(p) for p in parts_list)
616
+ common_depth = 0
617
+ for i in range(min_depth - 1):
618
+ seg = parts_list[0][i]
619
+ if all(pl[i] == seg for pl in parts_list):
620
+ common_depth = i + 1
621
+ else:
622
+ break
623
+
624
+ if common_depth < 3:
625
+ return None
626
+
627
+ module_files: dict[str, list[str]] = {}
628
+ for orig, pl in zip(paths, parts_list):
629
+ remaining = pl[common_depth:]
630
+ if remaining and remaining[0] not in _GENERIC_NAMES:
631
+ module_files.setdefault(remaining[0], []).append(orig)
632
+
633
+ meaningful = {k: v for k, v in module_files.items() if len(v) >= 2}
634
+ if len(meaningful) < 3:
635
+ return None
636
+
637
+ return "spring_mvc_layered", [
638
+ ArchitectureLayer(
639
+ name=k, pattern="spring_mvc_layered", files=v, confidence="medium"
640
+ )
641
+ for k, v in meaningful.items()
642
+ ]
643
+
595
644
  def _detect_microservices(
596
645
  self, paths: list[str]
597
646
  ) -> Optional[tuple[str, list[ArchitectureLayer]]]:
@@ -118,6 +118,10 @@ class TypeClassifier:
118
118
  ):
119
119
  return "webapp"
120
120
 
121
+ _SERVERSIDE_TEMPLATE_FRAMEWORKS = frozenset({"Thymeleaf", "FreeMarker"})
122
+ if framework_names & _SERVERSIDE_TEMPLATE_FRAMEWORKS:
123
+ return "web_mvc"
124
+
121
125
  if framework_names & _API_FRAMEWORKS:
122
126
  return "api"
123
127
 
@@ -140,7 +140,21 @@ def _check_pipeline_coherence(sm: "SourceMap") -> list[str]: # type: ignore[nam
140
140
 
141
141
  return issues
142
142
 
143
- _HELP = """\
143
+ def _build_help_text() -> str:
144
+ """Build --help text dynamically based on current license state."""
145
+ try:
146
+ from sourcecode.license import is_pro as _is_pro
147
+ except Exception:
148
+ _is_pro = False
149
+
150
+ if _is_pro:
151
+ plan_badge = "[bold green]● Pro[/bold green]"
152
+ else:
153
+ plan_badge = "[yellow]Free[/yellow] · [dim]sourcecode activate <key>[/dim] to unlock Pro"
154
+
155
+ text = f"""\
156
+ [bold]sourcecode[/bold] {plan_badge}
157
+
144
158
  Deterministic codebase context for AI coding agents.
145
159
 
146
160
  [bold]Primary usage:[/bold]
@@ -164,6 +178,26 @@ Deterministic codebase context for AI coding agents.
164
178
  version
165
179
  """
166
180
 
181
+ if not _is_pro:
182
+ text += """\
183
+
184
+ [dim bold]Locked (Pro):[/dim bold]
185
+ [dim]impact blast radius before any change[/dim]
186
+ [dim]modernize (full) dead zones, tangles, full coupling[/dim]
187
+ [dim]fix-bug (full) complete risk-ranked file list[/dim]
188
+ [dim]review-pr (expanded) CI-grade PR review[/dim]
189
+ [dim]prepare-context delta incremental context for CI/CD[/dim]
190
+ [dim]prepare-context generate-tests test gap analysis[/dim]
191
+ [dim]--full removes all truncation limits[/dim]
192
+
193
+ [dim cyan]→ sourcecode activate <key>[/dim cyan]
194
+ """
195
+
196
+ return text
197
+
198
+
199
+ _HELP = _build_help_text()
200
+
167
201
  # Known subcommand names — tokens matching these are routed as subcommands,
168
202
  # not consumed as a repository path.
169
203
  _SUBCOMMANDS: frozenset[str] = frozenset(
@@ -344,6 +378,10 @@ def _get_command_with_preprocessing(typer_instance: Any) -> Any:
344
378
  cmd = _orig_get_command(typer_instance)
345
379
  if typer_instance is not app:
346
380
  return cmd # only wrap the root app, not telemetry_app etc.
381
+
382
+ # Refresh help text at invocation time so it reflects current license state.
383
+ cmd.help = _build_help_text()
384
+
347
385
  _orig_cmd_main = cmd.main
348
386
 
349
387
  def _cmd_main(args: Optional[list[str]] = None, **kwargs: Any) -> Any:
@@ -2011,6 +2049,15 @@ def main(
2011
2049
  except Exception:
2012
2050
  pass # non-fatal: cache write failure
2013
2051
 
2052
+ # Update RIS with aggregated snapshot data (non-fatal side-effect).
2053
+ if not no_cache and not _pipeline_error and _core_key:
2054
+ try:
2055
+ from sourcecode.serializer import core_view as _ris_core_view
2056
+ from sourcecode.ris import maybe_update_ris as _ris_update
2057
+ _ris_update(target, _ris_core_view(sm), _git_sha)
2058
+ except Exception:
2059
+ pass
2060
+
2014
2061
  if _pipeline_error:
2015
2062
  raise typer.Exit(code=2)
2016
2063
 
@@ -3147,6 +3194,14 @@ def endpoints_cmd(
3147
3194
  raise typer.Exit(code=1)
3148
3195
 
3149
3196
  data = _extract_java_endpoints(target)
3197
+
3198
+ # Update RIS api_surface section (non-fatal side-effect).
3199
+ try:
3200
+ from sourcecode.ris import update_ris_api_surface as _ris_ep
3201
+ _ris_ep(target, data)
3202
+ except Exception:
3203
+ pass
3204
+
3150
3205
  output = _serialize_dict(data, format)
3151
3206
 
3152
3207
  if output_path is not None:
@@ -3824,7 +3879,7 @@ def mcp_init(
3824
3879
  raise typer.Exit(code=1)
3825
3880
 
3826
3881
  typer.echo("MCP integration active.")
3827
- typer.echo(" Note: repo_path debe usar forward slashes: C:/Users/... o /ruta/unix")
3882
+ typer.echo(" Note: repo_path must use forward slashes: C:/Users/... or /unix/path")
3828
3883
  typer.echo("")
3829
3884
 
3830
3885
  # Post-write: validate config and warn if client not running
@@ -3976,7 +4031,7 @@ def mcp_status() -> None:
3976
4031
  typer.echo(sep)
3977
4032
  typer.echo(" Note: 'configured' and 'running' are checked independently.")
3978
4033
  typer.echo(" A running app still needs restart after first-time config.")
3979
- typer.echo(" Path: repo_path debe usar forward slashes: C:/Users/... o /ruta/unix")
4034
+ typer.echo(" Path: repo_path must use forward slashes: C:/Users/... or /unix/path")
3980
4035
  typer.echo(" Setup: sourcecode mcp init")
3981
4036
  typer.echo(" Remove: sourcecode mcp remove")
3982
4037
 
@@ -28,6 +28,7 @@ _STACK_LABELS: dict[str, str] = {
28
28
 
29
29
  _TYPE_LABELS: dict[str, str] = {
30
30
  "api": "REST API",
31
+ "web_mvc": "Spring MVC web app",
31
32
  "webapp": "Web app",
32
33
  "fullstack": "Full-stack app",
33
34
  "cli": "CLI tool",
@@ -1118,7 +1118,7 @@ class DependencyAnalyzer:
1118
1118
  try:
1119
1119
  tree = ET.parse(pom)
1120
1120
  except (ET.ParseError, OSError):
1121
- return [], ["java: error al parsear pom.xml"]
1121
+ return [], ["java: error parsing pom.xml"]
1122
1122
 
1123
1123
  root_elem = tree.getroot()
1124
1124
  ns_match = re.match(r"\{[^}]+\}", root_elem.tag)
@@ -1217,10 +1217,10 @@ class DependencyAnalyzer:
1217
1217
  try:
1218
1218
  content = gradle_file.read_text(encoding="utf-8", errors="replace")
1219
1219
  except OSError:
1220
- return [], [f"gradle: error al leer {filename}"]
1220
+ return [], [f"gradle: error reading {filename}"]
1221
1221
  props = self._parse_gradle_properties(root, content)
1222
1222
  records = self._parse_gradle_dependencies(content, props, filename)
1223
- return records, ["gradle: sin lockfile compatible; dependencias transitivas no disponibles"]
1223
+ return records, ["gradle: no compatible lockfile found; transitive dependencies unavailable"]
1224
1224
  return [], []
1225
1225
 
1226
1226
  def _parse_gradle_properties(self, root: Path, content: str) -> dict[str, str]:
@@ -23,6 +23,7 @@ _MAX_ANNOTATION_ENTRY_POINTS = 1000
23
23
  _REST_CONTROLLER_RE = re.compile(r'@RestController\b')
24
24
  _MVC_CONTROLLER_RE = re.compile(r'@Controller\b')
25
25
  _REQUEST_MAPPING_RE = re.compile(r'@RequestMapping\b')
26
+ _ANY_MAPPING_RE = re.compile(r'@(?:Request|Get|Post|Put|Delete|Patch)Mapping\b')
26
27
  _CONTROLLER_ADVICE_RE = re.compile(r'@ControllerAdvice\b')
27
28
  _WEB_FILTER_RE = re.compile(r'@WebFilter\b')
28
29
  _FILTER_BEAN_RE = re.compile(r'FilterRegistrationBean\b')
@@ -298,6 +299,10 @@ class JavaDetector(AbstractDetector):
298
299
  frameworks.append(FrameworkDetection(name="Jakarta EE", source=source))
299
300
  if "mybatis" in text:
300
301
  frameworks.append(FrameworkDetection(name="MyBatis", source=source))
302
+ if "thymeleaf" in text:
303
+ frameworks.append(FrameworkDetection(name="Thymeleaf", source=source))
304
+ if "freemarker" in text:
305
+ frameworks.append(FrameworkDetection(name="FreeMarker", source=source))
301
306
  if "spring-boot-starter-security" in text or "spring-security-core" in text:
302
307
  frameworks.append(FrameworkDetection(name="Spring Security", source=source))
303
308
  if "spring-boot-starter-data-jpa" in text or "spring-data-jpa" in text:
@@ -470,7 +475,7 @@ class JavaDetector(AbstractDetector):
470
475
  path=rel_path, stack="java", kind="exception_handler",
471
476
  source="annotation", confidence="medium",
472
477
  )]
473
- if _MVC_CONTROLLER_RE.search(content) and _REQUEST_MAPPING_RE.search(content):
478
+ if _MVC_CONTROLLER_RE.search(content) and _ANY_MAPPING_RE.search(content):
474
479
  http_path_match = _HTTP_PATH_RE.search(content)
475
480
  http_path = http_path_match.group(1) if http_path_match else None
476
481
  verb_match = _REQUEST_METHOD_VERB_RE.search(content)
@@ -109,6 +109,42 @@ def _check_repo_path(path: str) -> "CallToolResult | None":
109
109
  return None
110
110
 
111
111
 
112
+ @mcp.tool()
113
+ def get_cold_start_context(repo_path: str = ".") -> dict:
114
+ """Instant session bootstrap from persisted Repository Intelligence Snapshot (RIS).
115
+
116
+ CALL THIS FIRST at the start of every MCP session. Returns cached structural
117
+ context built from prior analysis runs — zero re-analysis cost.
118
+
119
+ status values:
120
+ "cold_start_ready" — RIS exists and matches the current git HEAD.
121
+ "cold_start_stale" — RIS exists but HEAD has changed since last analysis.
122
+ Data is still useful; run get_compact_context to refresh.
123
+ "no_ris" — No RIS yet for this repo; run get_compact_context first.
124
+
125
+ Returns: status, repo_id, git_head, stale (bool), last_updated_at,
126
+ summary (compact snapshot), entrypoints, endpoints, hotspots.
127
+
128
+ repo_path: absolute path to the repository (default: current working directory).
129
+ """
130
+ _raw = repo_path
131
+ try:
132
+ if not isinstance(repo_path, str):
133
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
134
+ repo_path = _normalize_repo_path(repo_path)
135
+ _path_err = _check_repo_path(repo_path)
136
+ if _path_err is not None:
137
+ return _path_err
138
+ from pathlib import Path as _Path
139
+ from sourcecode.ris import get_cold_start_context as _gcs
140
+ return _ok(_gcs(_Path(repo_path)))
141
+ except Exception as exc:
142
+ return _err(
143
+ f"Internal error: {type(exc).__name__}: {exc} — repo_path: {_raw}",
144
+ "INTERNAL_ERROR",
145
+ )
146
+
147
+
112
148
  @mcp.tool()
113
149
  def get_compact_context(repo_path: str = ".", git_context: bool = False) -> dict:
114
150
  """Compact human/LLM summary of a repository (~1000-3000 tokens). USE THIS FIRST.
@@ -981,12 +981,18 @@ class TaskContextBuilder:
981
981
 
982
982
  dep_records, dep_summary = DependencyAnalyzer().analyze(self.root)
983
983
  primary_eco = stacks[0].stack if stacks else ""
984
- direct = [
984
+ _direct_raw = [
985
985
  d for d in dep_records
986
986
  if d.scope != "transitive" and d.source in {"manifest", "lockfile"}
987
987
  and (d.role or "unknown") in {"runtime", "parsing", "serialization", "observability", "infra"}
988
988
  and d.scope not in {"dev"}
989
989
  ]
990
+ _seen_dep: set[str] = set()
991
+ direct = []
992
+ for _d in _direct_raw:
993
+ if _d.name not in _seen_dep:
994
+ _seen_dep.add(_d.name)
995
+ direct.append(_d)
990
996
  # Rank by framework centrality: core infra (ORM, Spring) > serialization > other.
991
997
  # Penalise vendored tooling (closure-compiler, shaded utilities) so that
992
998
  # Hibernate/JPA/Solr appear before minor build-time dependencies.
@@ -1697,6 +1697,9 @@ def _canonical_subsystem_pkg(fqn: str) -> str:
1697
1697
  (even if uppercase) to force at least 2-segment grouping.
1698
1698
  """
1699
1699
  _TOP_LEVEL = {"com", "org", "net", "io", "java", "javax"}
1700
+ # Well-known framework namespaces that are not application boundaries;
1701
+ # go one level deeper (depth 5) so callers get the actual app module.
1702
+ _FRAMEWORK_NS = {"springframework", "apache", "eclipse", "google", "jetbrains"}
1700
1703
  parts: list[str] = []
1701
1704
  for segment in fqn.split("."):
1702
1705
  if "#" in segment or (segment and segment[0].isupper()):
@@ -1705,6 +1708,8 @@ def _canonical_subsystem_pkg(fqn: str) -> str:
1705
1708
  if not parts:
1706
1709
  return fqn.rsplit(".", 1)[0] if "." in fqn else fqn
1707
1710
  if parts[0] in _TOP_LEVEL and len(parts) >= 3:
1711
+ if len(parts) >= 5 and len(parts) > 3 and parts[1] in _FRAMEWORK_NS:
1712
+ return ".".join(parts[:5])
1708
1713
  return ".".join(parts[:3])
1709
1714
  # Prevent bare TLD collapse: "org" or "com" alone as subsystem key is meaningless
1710
1715
  # and groups ALL classes under that TLD into a single giant component.
@@ -3338,7 +3343,7 @@ def compute_blast_radius(
3338
3343
  _seen_mapper_fqns.add(fqn)
3339
3344
  _mapper_entry: dict = {
3340
3345
  "fqn": fqn,
3341
- "role": role or "mapper",
3346
+ "role": role or ("mapper" if symbol_kind == "mapper_interface" else "repository"),
3342
3347
  "source_file": node_dict.get("source_file") or "",
3343
3348
  }
3344
3349
  if canonical != fqn: