sourcecode 1.31.0__tar.gz → 1.31.1__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 (216) hide show
  1. {sourcecode-1.31.0 → sourcecode-1.31.1}/PKG-INFO +4 -3
  2. {sourcecode-1.31.0 → sourcecode-1.31.1}/README.md +2 -2
  3. {sourcecode-1.31.0 → sourcecode-1.31.1}/pyproject.toml +2 -1
  4. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/cli.py +81 -25
  6. sourcecode-1.31.1/src/sourcecode/mcp/onboarding/detector.py +104 -0
  7. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/mcp/runner.py +10 -3
  8. sourcecode-1.31.1/src/sourcecode/mcp/server.py +119 -0
  9. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_mcp_runner.py +3 -3
  10. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_mcp_serve.py +0 -8
  11. sourcecode-1.31.1/tests/test_mcp_tools.py +222 -0
  12. sourcecode-1.31.0/.sourcecode-cache/snapshot-0e430c1-37df4554.json +0 -262
  13. sourcecode-1.31.0/.sourcecode-cache/snapshot-0e430c1-e9801942.json +0 -219
  14. sourcecode-1.31.0/.sourcecode-cache/snapshot-0e430c1-ee60e0cd.json +0 -326
  15. sourcecode-1.31.0/src/sourcecode/mcp/onboarding/detector.py +0 -59
  16. sourcecode-1.31.0/src/sourcecode/mcp/server.py +0 -147
  17. sourcecode-1.31.0/tests/test_mcp_tools.py +0 -242
  18. {sourcecode-1.31.0 → sourcecode-1.31.1}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
  19. {sourcecode-1.31.0 → sourcecode-1.31.1}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
  20. {sourcecode-1.31.0 → sourcecode-1.31.1}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
  21. {sourcecode-1.31.0 → sourcecode-1.31.1}/.continue-here.md +0 -0
  22. {sourcecode-1.31.0 → sourcecode-1.31.1}/.github/workflows/build-windows.yml +0 -0
  23. {sourcecode-1.31.0 → sourcecode-1.31.1}/.gitignore +0 -0
  24. {sourcecode-1.31.0 → sourcecode-1.31.1}/.ruff.toml +0 -0
  25. {sourcecode-1.31.0 → sourcecode-1.31.1}/CHANGELOG.md +0 -0
  26. {sourcecode-1.31.0 → sourcecode-1.31.1}/CONTRIBUTING.md +0 -0
  27. {sourcecode-1.31.0 → sourcecode-1.31.1}/LICENSE +0 -0
  28. {sourcecode-1.31.0 → sourcecode-1.31.1}/SECURITY.md +0 -0
  29. {sourcecode-1.31.0 → sourcecode-1.31.1}/docs/privacy.md +0 -0
  30. {sourcecode-1.31.0 → sourcecode-1.31.1}/docs/schema.md +0 -0
  31. {sourcecode-1.31.0 → sourcecode-1.31.1}/raw +0 -0
  32. {sourcecode-1.31.0 → sourcecode-1.31.1}/run_cli.py +0 -0
  33. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/adaptive_scanner.py +0 -0
  34. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/architecture_analyzer.py +0 -0
  35. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/architecture_summary.py +0 -0
  36. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/ast_extractor.py +0 -0
  37. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/classifier.py +0 -0
  38. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/code_notes_analyzer.py +0 -0
  39. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/confidence_analyzer.py +0 -0
  40. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/context_scorer.py +0 -0
  41. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/context_summarizer.py +0 -0
  42. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/contract_model.py +0 -0
  43. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/contract_pipeline.py +0 -0
  44. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/coverage_parser.py +0 -0
  45. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/dependency_analyzer.py +0 -0
  46. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/__init__.py +0 -0
  47. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/base.py +0 -0
  48. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/csproj_parser.py +0 -0
  49. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/dart.py +0 -0
  50. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/dotnet.py +0 -0
  51. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/elixir.py +0 -0
  52. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/go.py +0 -0
  53. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/heuristic.py +0 -0
  54. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/hybrid.py +0 -0
  55. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/java.py +0 -0
  56. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/jvm_ext.py +0 -0
  57. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/nodejs.py +0 -0
  58. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/parsers.py +0 -0
  59. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/php.py +0 -0
  60. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/project.py +0 -0
  61. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/python.py +0 -0
  62. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/ruby.py +0 -0
  63. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/rust.py +0 -0
  64. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/systems.py +0 -0
  65. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/terraform.py +0 -0
  66. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/detectors/tooling.py +0 -0
  67. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/doc_analyzer.py +0 -0
  68. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/entrypoint_classifier.py +0 -0
  69. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/env_analyzer.py +0 -0
  70. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/file_classifier.py +0 -0
  71. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/flow_analyzer.py +0 -0
  72. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/git_analyzer.py +0 -0
  73. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/graph_analyzer.py +0 -0
  74. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/mcp/__init__.py +0 -0
  75. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  76. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  77. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  78. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  79. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/metrics_analyzer.py +0 -0
  80. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/pr_comment_renderer.py +0 -0
  81. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/prepare_context.py +0 -0
  82. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/progress.py +0 -0
  83. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/ranking_engine.py +0 -0
  84. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/redactor.py +0 -0
  85. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/relevance_scorer.py +0 -0
  86. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/repo_classifier.py +0 -0
  87. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/repository_ir.py +0 -0
  88. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/runtime_classifier.py +0 -0
  89. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/scanner.py +0 -0
  90. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/schema.py +0 -0
  91. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/semantic_analyzer.py +0 -0
  92. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/serializer.py +0 -0
  93. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/summarizer.py +0 -0
  94. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/telemetry/__init__.py +0 -0
  95. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/telemetry/config.py +0 -0
  96. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/telemetry/consent.py +0 -0
  97. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/telemetry/events.py +0 -0
  98. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/telemetry/filters.py +0 -0
  99. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/telemetry/transport.py +0 -0
  100. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/tree_utils.py +0 -0
  101. {sourcecode-1.31.0 → sourcecode-1.31.1}/src/sourcecode/workspace.py +0 -0
  102. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/__init__.py +0 -0
  103. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/conftest.py +0 -0
  104. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/coverage.xml +0 -0
  105. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
  106. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/fastapi_app/src/main.py +0 -0
  107. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/go_service/cmd/api/main.go +0 -0
  108. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/go_service/go.mod +0 -0
  109. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/jacoco.xml +0 -0
  110. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/latin1_sample.java +0 -0
  111. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/latin1_sample_iso.java +0 -0
  112. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/lcov.info +0 -0
  113. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
  114. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/nextjs_app/package.json +0 -0
  115. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
  116. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
  117. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
  118. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
  119. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
  120. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
  121. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
  122. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
  123. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
  124. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
  125. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
  126. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
  127. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
  128. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
  129. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
  130. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
  131. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
  132. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
  133. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
  134. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
  135. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
  136. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
  137. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
  138. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
  139. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
  140. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
  141. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
  142. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
  143. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
  144. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
  145. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
  146. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
  147. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
  148. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_architecture_analyzer.py +0 -0
  149. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_architecture_summary.py +0 -0
  150. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_ast_extractor.py +0 -0
  151. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_block1_reliability.py +0 -0
  152. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_block2_coverage.py +0 -0
  153. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_block5_quality.py +0 -0
  154. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_bug_fixes_v1302.py +0 -0
  155. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_bug_fixes_v16.py +0 -0
  156. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_bug_fixes_v2.py +0 -0
  157. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_classifier.py +0 -0
  158. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_cli.py +0 -0
  159. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_code_notes_analyzer.py +0 -0
  160. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_context_scorer.py +0 -0
  161. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_contract_pipeline.py +0 -0
  162. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_coverage_parser.py +0 -0
  163. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_cross_consistency.py +0 -0
  164. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_dependency_analyzer_node_python.py +0 -0
  165. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_dependency_analyzer_polyglot.py +0 -0
  166. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_dependency_schema.py +0 -0
  167. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_dotnet.py +0 -0
  168. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_go_rust_java.py +0 -0
  169. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_nodejs.py +0 -0
  170. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_php_ruby_dart.py +0 -0
  171. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_python.py +0 -0
  172. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_universal_managed.py +0 -0
  173. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detector_universal_systems.py +0 -0
  174. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_detectors_base.py +0 -0
  175. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_doc_analyzer_jsdom.py +0 -0
  176. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_doc_analyzer_python.py +0 -0
  177. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_encoding_regression.py +0 -0
  178. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_graph_analyzer_polyglot.py +0 -0
  179. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_graph_analyzer_python_node.py +0 -0
  180. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_graph_schema.py +0 -0
  181. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_hybrid_inference.py +0 -0
  182. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration.py +0 -0
  183. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_dependencies.py +0 -0
  184. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_detection.py +0 -0
  185. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_docs.py +0 -0
  186. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_graph_modules.py +0 -0
  187. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_lqn.py +0 -0
  188. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_metrics.py +0 -0
  189. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_multistack.py +0 -0
  190. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_semantics.py +0 -0
  191. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_integration_universal.py +0 -0
  192. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_java_spring_integration.py +0 -0
  193. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_metrics_analyzer.py +0 -0
  194. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_output_ux.py +0 -0
  195. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_packaging.py +0 -0
  196. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_phase1_improvements.py +0 -0
  197. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_pipeline_integrity.py +0 -0
  198. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_real_projects.py +0 -0
  199. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_redactor.py +0 -0
  200. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_repository_ir.py +0 -0
  201. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_scanner.py +0 -0
  202. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_schema.py +0 -0
  203. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_schema_normalization.py +0 -0
  204. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_scoring_calibration.py +0 -0
  205. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_semantic_analyzer_node.py +0 -0
  206. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_semantic_analyzer_python.py +0 -0
  207. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_semantic_import_resolution.py +0 -0
  208. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_semantic_schema.py +0 -0
  209. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_signal_hierarchy.py +0 -0
  210. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_summarizer.py +0 -0
  211. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_surface_honesty.py +0 -0
  212. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_task_differentiation.py +0 -0
  213. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_telemetry.py +0 -0
  214. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_v131_improvements.py +0 -0
  215. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_v1_10_regressions.py +0 -0
  216. {sourcecode-1.31.0 → sourcecode-1.31.1}/tests/test_workspace_analyzer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.31.0
3
+ Version: 1.31.1
4
4
  Summary: Deterministic codebase context for AI coding agents
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -203,6 +203,7 @@ Classifier: Programming Language :: Python :: 3.12
203
203
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
204
204
  Classifier: Topic :: Utilities
205
205
  Requires-Python: >=3.9
206
+ Requires-Dist: mcp>=1.0.0
206
207
  Requires-Dist: pathspec>=1.0
207
208
  Requires-Dist: ruamel-yaml>=0.18
208
209
  Requires-Dist: tomli>=2.0; python_version < '3.11'
@@ -224,7 +225,7 @@ Description-Content-Type: text/markdown
224
225
 
225
226
  **Deterministic, behavior-aware codebase context for AI agents and PR review.**
226
227
 
227
- ![Version](https://img.shields.io/badge/version-1.31.0-blue)
228
+ ![Version](https://img.shields.io/badge/version-1.31.1-blue)
228
229
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
229
230
 
230
231
  ---
@@ -260,7 +261,7 @@ pipx install sourcecode
260
261
 
261
262
  ```bash
262
263
  sourcecode version
263
- # sourcecode 1.31.0
264
+ # sourcecode 1.31.1
264
265
  ```
265
266
 
266
267
  ---
@@ -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.31.0-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.31.1-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.31.0
41
+ # sourcecode 1.31.1
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.31.0"
7
+ version = "1.31.1"
8
8
  description = "Deterministic codebase context for AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -29,6 +29,7 @@ dependencies = [
29
29
  "pathspec>=1.0",
30
30
  "ruamel.yaml>=0.18",
31
31
  "tomli>=2.0; python_version < '3.11'",
32
+ "mcp>=1.0.0",
32
33
  ]
33
34
 
34
35
  [project.scripts]
@@ -1,3 +1,3 @@
1
1
  """sourcecode — Deterministic codebase context maps for AI coding agents."""
2
2
 
3
- __version__ = "1.31.0"
3
+ __version__ = "1.31.1"
@@ -2466,10 +2466,6 @@ def analyze_cmd(
2466
2466
  def mcp_serve() -> None:
2467
2467
  """Start the MCP server on stdio for AI agent integration.
2468
2468
 
2469
- \b
2470
- Requires the 'mcp' extra:
2471
- pip install sourcecode[mcp]
2472
-
2473
2469
  \b
2474
2470
  Configure in your MCP client (e.g. Claude Desktop):
2475
2471
  {
@@ -2487,15 +2483,7 @@ def mcp_serve() -> None:
2487
2483
  level=logging.INFO,
2488
2484
  format="[sourcecode-mcp] %(levelname)s %(message)s",
2489
2485
  )
2490
- try:
2491
- from sourcecode.mcp.server import mcp as _mcp
2492
- except ImportError:
2493
- typer.echo(
2494
- "MCP support not available. Install with:\n"
2495
- " pip install sourcecode[mcp]",
2496
- err=True,
2497
- )
2498
- raise typer.Exit(code=1)
2486
+ from sourcecode.mcp.server import mcp as _mcp
2499
2487
 
2500
2488
  log = logging.getLogger(__name__)
2501
2489
  log.info("sourcecode-mcp starting (stdio transport)")
@@ -2513,21 +2501,44 @@ def mcp_serve() -> None:
2513
2501
  @mcp_app.command("init")
2514
2502
  def mcp_init(
2515
2503
  yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt."),
2504
+ target: Optional[str] = typer.Option(
2505
+ None,
2506
+ "--target",
2507
+ "-t",
2508
+ help="Target client: claude-desktop | cursor. Default: auto-detect all.",
2509
+ ),
2516
2510
  ) -> None:
2517
2511
  """Setup MCP integration for Claude Desktop, Cursor, and other clients.
2518
2512
 
2519
2513
  \b
2520
2514
  Detects installed MCP clients, backs up their config files, and safely
2521
2515
  inserts the sourcecode server entry. Fully idempotent — safe to re-run.
2516
+
2517
+ \b
2518
+ Examples:
2519
+ sourcecode mcp init
2520
+ sourcecode mcp init --target claude-desktop
2521
+ sourcecode mcp init --target cursor --yes
2522
2522
  """
2523
- from sourcecode.mcp.onboarding.detector import detect_clients
2523
+ from sourcecode.mcp.onboarding.detector import detect_clients, is_client_running
2524
2524
  from sourcecode.mcp.onboarding.planner import build_install_plan
2525
2525
  from sourcecode.mcp.onboarding import backup, applier
2526
2526
 
2527
2527
  typer.echo("Detecting MCP clients...")
2528
2528
  typer.echo("")
2529
2529
 
2530
- clients = detect_clients()
2530
+ all_clients = detect_clients()
2531
+
2532
+ if target:
2533
+ target_slug = target.lower()
2534
+ clients = [c for c in all_clients if c.slug == target_slug]
2535
+ if not clients:
2536
+ valid = ", ".join(c.slug for c in all_clients)
2537
+ typer.echo(f"Unknown target '{target}'. Valid: {valid}", err=True)
2538
+ raise typer.Exit(code=1)
2539
+ else:
2540
+ clients = all_clients
2541
+
2531
2542
  if not clients:
2532
2543
  typer.echo("No MCP clients found on this system.")
2533
2544
  typer.echo("")
@@ -2603,36 +2614,81 @@ def mcp_init(
2603
2614
  typer.echo("MCP integration active.")
2604
2615
  typer.echo("")
2605
2616
 
2606
- restart_needed = [a.client.name for a in actionable if not a.will_create_file]
2607
- if restart_needed:
2608
- typer.echo(f" Restart {', '.join(restart_needed)} to apply changes.")
2617
+ # Post-write: validate config and warn if client not running
2618
+ for a in actionable:
2619
+ if not is_client_running(a.client):
2620
+ typer.echo(
2621
+ f" ⚠ Config written but {a.client.name} is not running. "
2622
+ f"Start {a.client.name} and run sourcecode mcp status to verify.",
2623
+ err=False,
2624
+ )
2625
+ else:
2626
+ restart_msg = "" if a.will_create_file else f" Restart {a.client.name} to apply."
2627
+ typer.echo(f" ✓ {a.client.name} is running.{restart_msg}")
2628
+
2629
+ typer.echo("")
2609
2630
  typer.echo(" Remove: sourcecode mcp remove")
2610
2631
 
2611
2632
 
2612
2633
  @mcp_app.command("status")
2613
2634
  def mcp_status() -> None:
2614
- """Show MCP integration status for all detected clients."""
2615
- from sourcecode.mcp.onboarding.detector import detect_clients
2635
+ """Show MCP integration status: dependencies, config files, and connectivity."""
2636
+ from sourcecode.mcp.onboarding.detector import detect_clients, is_client_running
2616
2637
  from sourcecode.mcp.onboarding import applier
2617
2638
 
2618
- clients = detect_clients()
2619
- typer.echo("MCP Integration Status")
2639
+ sep = "─" * 46
2640
+
2641
+ typer.echo("MCP Status")
2642
+ typer.echo(sep)
2643
+
2644
+ # Stage 1: Dependencies
2645
+ try:
2646
+ import mcp as _mcp_pkg # noqa: F401
2647
+ typer.echo("Dependencies ✓ installed")
2648
+ except ImportError:
2649
+ typer.echo("Dependencies ✗ missing")
2650
+ typer.echo(" Fix: pip install sourcecode[mcp]")
2620
2651
  typer.echo("")
2621
2652
 
2653
+ clients = detect_clients()
2622
2654
  if not clients:
2623
2655
  typer.echo(" No MCP clients detected on this system.")
2656
+ typer.echo(sep)
2657
+ typer.echo(" Setup: sourcecode mcp init")
2624
2658
  raise typer.Exit(code=0)
2625
2659
 
2660
+ # Stage 2: Config files
2661
+ typer.echo("Config files")
2626
2662
  for client in clients:
2627
2663
  if not client.app_installed:
2628
- typer.echo(f" {client.name:<18} not found")
2664
+ typer.echo(f" {client.name:<20} not found")
2665
+ typer.echo(f" Expected: {client.config_path}")
2666
+ typer.echo(f" Fix: sourcecode mcp init --target {client.slug}")
2629
2667
  continue
2630
2668
  config = applier.read_config(client.config_path)
2631
2669
  if applier.is_installed(config):
2632
- typer.echo(f" {client.name:<18} configured {client.config_path}")
2670
+ typer.echo(f" {client.name:<20} configured {client.config_path}")
2633
2671
  else:
2634
- typer.echo(f" {client.name:<18} not configured")
2672
+ typer.echo(f" {client.name:<20} not configured")
2673
+ typer.echo(f" Fix: sourcecode mcp init --target {client.slug}")
2635
2674
  typer.echo("")
2675
+
2676
+ # Stage 3: Connectivity
2677
+ typer.echo("Connectivity")
2678
+ any_installed = any(c.app_installed for c in clients)
2679
+ if not any_installed:
2680
+ typer.echo(" (no clients to check)")
2681
+ else:
2682
+ for client in clients:
2683
+ if not client.app_installed:
2684
+ continue
2685
+ if is_client_running(client):
2686
+ typer.echo(f" {client.name:<20} ✓ running")
2687
+ else:
2688
+ typer.echo(f" {client.name:<20} ✗ not running")
2689
+ typer.echo(f" Fix: open {client.name}, then run sourcecode mcp status")
2690
+
2691
+ typer.echo(sep)
2636
2692
  typer.echo(" Setup: sourcecode mcp init")
2637
2693
  typer.echo(" Remove: sourcecode mcp remove")
2638
2694
 
@@ -0,0 +1,104 @@
1
+ """Detect MCP-capable clients installed on the current machine."""
2
+ from __future__ import annotations
3
+
4
+ import os
5
+ import subprocess
6
+ import sys
7
+ from dataclasses import dataclass
8
+ from pathlib import Path
9
+ from typing import Any, Dict, List
10
+
11
+
12
+ _CLIENT_REGISTRY: List[Dict[str, Any]] = [
13
+ {
14
+ "name": "Claude Desktop",
15
+ "slug": "claude-desktop",
16
+ "paths": {
17
+ "darwin": "~/Library/Application Support/Claude/claude_desktop_config.json",
18
+ "linux": "~/.config/Claude/claude_desktop_config.json",
19
+ "win32": "{APPDATA}/Claude/claude_desktop_config.json",
20
+ },
21
+ "process": {
22
+ "darwin": "Claude",
23
+ "linux": "claude-desktop",
24
+ "win32": "Claude",
25
+ },
26
+ },
27
+ {
28
+ "name": "Cursor",
29
+ "slug": "cursor",
30
+ "paths": {
31
+ "darwin": "~/.cursor/mcp.json",
32
+ "linux": "~/.cursor/mcp.json",
33
+ "win32": "{USERPROFILE}/.cursor/mcp.json",
34
+ },
35
+ "process": {
36
+ "darwin": "Cursor",
37
+ "linux": "cursor",
38
+ "win32": "Cursor",
39
+ },
40
+ },
41
+ ]
42
+
43
+
44
+ @dataclass(frozen=True)
45
+ class MCPClient:
46
+ name: str
47
+ config_path: Path
48
+ app_installed: bool # True if the config file (or its parent dir) exists
49
+ process_name: str # OS process name for connectivity check
50
+ slug: str # --target identifier (e.g. "claude-desktop")
51
+
52
+
53
+ def _resolve(template: str) -> Path:
54
+ """Expand env vars in Windows-style {VAR} templates, then expanduser."""
55
+ result = template
56
+ for var in ("APPDATA", "LOCALAPPDATA", "USERPROFILE"):
57
+ val = os.environ.get(var, "")
58
+ if val:
59
+ result = result.replace(f"{{{var}}}", val)
60
+ return Path(result).expanduser()
61
+
62
+
63
+ def detect_clients() -> list[MCPClient]:
64
+ """Return all known MCP clients with their resolved config paths."""
65
+ plat = sys.platform
66
+ clients: list[MCPClient] = []
67
+ for entry in _CLIENT_REGISTRY:
68
+ paths: Dict[str, str] = entry["paths"]
69
+ processes: Dict[str, str] = entry["process"]
70
+ template = paths.get(plat) or paths.get("linux", "")
71
+ if not template:
72
+ continue
73
+ config_path = _resolve(template)
74
+ app_installed = config_path.exists() or config_path.parent.exists()
75
+ process_name = processes.get(plat) or processes.get("linux", "")
76
+ clients.append(MCPClient(
77
+ name=entry["name"],
78
+ config_path=config_path,
79
+ app_installed=app_installed,
80
+ process_name=process_name,
81
+ slug=entry["slug"],
82
+ ))
83
+ return clients
84
+
85
+
86
+ def is_client_running(client: MCPClient) -> bool:
87
+ """True if the client process is currently running."""
88
+ if not client.process_name:
89
+ return False
90
+ try:
91
+ if sys.platform == "win32":
92
+ result = subprocess.run(
93
+ ["tasklist", "/fi", f"imagename eq {client.process_name}.exe"],
94
+ capture_output=True, text=True, timeout=5,
95
+ )
96
+ return client.process_name.lower() in result.stdout.lower()
97
+ else:
98
+ result = subprocess.run(
99
+ ["pgrep", "-x", client.process_name],
100
+ capture_output=True, timeout=5,
101
+ )
102
+ return result.returncode == 0
103
+ except Exception:
104
+ return False
@@ -6,14 +6,18 @@ lookup, no process fork, no stdout encoding issues.
6
6
  """
7
7
  from __future__ import annotations
8
8
 
9
+ import json
10
+ from typing import Any
11
+
9
12
  from typer.testing import CliRunner
10
13
 
11
14
  _runner = CliRunner()
12
15
 
13
16
 
14
- def run_command(args: list[str]) -> str:
15
- """Invoke a sourcecode CLI command in-process and return stdout.
17
+ def run_command(args: list[str]) -> Any:
18
+ """Invoke a sourcecode CLI command in-process and return parsed output.
16
19
 
20
+ Returns parsed JSON dict when output is valid JSON, else the raw string.
17
21
  Raises RuntimeError on non-zero exit or empty output.
18
22
  """
19
23
  from sourcecode.cli import _detected_path, _preprocess_args, app
@@ -37,4 +41,7 @@ def run_command(args: list[str]) -> str:
37
41
  f"Args: {args}"
38
42
  )
39
43
 
40
- return output
44
+ try:
45
+ return json.loads(output)
46
+ except json.JSONDecodeError:
47
+ return output
@@ -0,0 +1,119 @@
1
+ """MCP server for sourcecode CLI.
2
+
3
+ Exposes sourcecode capabilities as MCP tools. Each tool maps to a CLI command
4
+ and delegates execution to the in-process runner — no subprocess, no binary
5
+ lookup, same process as the CLI.
6
+
7
+ All tools return:
8
+ {"success": bool, "data": dict | str | None, "error": {"code": str, "message": str} | None}
9
+ data is the parsed JSON object from the CLI output, not a shell string.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ from typing import Any
15
+
16
+ from mcp.server.fastmcp import FastMCP
17
+
18
+ from sourcecode.mcp.runner import run_command
19
+
20
+ mcp = FastMCP("sourcecode")
21
+
22
+
23
+ def _ok(data: Any) -> dict:
24
+ return {"success": True, "data": data, "error": None}
25
+
26
+
27
+ def _err(message: str, code: str = "EXECUTION_FAILED") -> dict:
28
+ return {"success": False, "data": None, "error": {"code": code, "message": message}}
29
+
30
+
31
+ def _execute(args: list[str]) -> dict:
32
+ try:
33
+ return _ok(run_command(args))
34
+ except RuntimeError as exc:
35
+ return _err(str(exc))
36
+
37
+
38
+ @mcp.tool()
39
+ def get_compact_context(repo_path: str = ".") -> dict:
40
+ """High-signal summary of a repository (~1000-3000 tokens).
41
+
42
+ Maps to: sourcecode <repo_path> --compact
43
+ Returns: stacks, entry points, dependency summary, confidence, gaps.
44
+ repo_path: absolute path to the repository (default: current working directory).
45
+ """
46
+ if not isinstance(repo_path, str):
47
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
48
+ return _execute([repo_path, "--compact"])
49
+
50
+
51
+ @mcp.tool()
52
+ def get_agent_context(repo_path: str = ".") -> dict:
53
+ """Agent-optimised analysis: identity, entry points, dependencies, gaps.
54
+
55
+ Maps to: sourcecode <repo_path> --agent
56
+ Returns: structured noise-free JSON for AI agents.
57
+ repo_path: absolute path to the repository (default: current working directory).
58
+ """
59
+ if not isinstance(repo_path, str):
60
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
61
+ return _execute([repo_path, "--agent"])
62
+
63
+
64
+ @mcp.tool()
65
+ def get_endpoints(repo_path: str = ".") -> dict:
66
+ """API endpoint surface extraction.
67
+
68
+ Maps to: sourcecode <repo_path> --endpoints (pending CLI implementation)
69
+ repo_path: absolute path to the repository (default: current working directory).
70
+ """
71
+ return _err(
72
+ "get_endpoints requires --endpoints CLI flag (pending implementation). "
73
+ "Use get_compact_context for now — the output includes api_endpoint-classified files.",
74
+ "NOT_IMPLEMENTED",
75
+ )
76
+
77
+
78
+ @mcp.tool()
79
+ def get_module_context(repo_path: str = ".", module: str = "") -> dict:
80
+ """Compact analysis of a specific module or subdirectory within a repository.
81
+
82
+ Maps to: sourcecode <repo_path>/<module> --compact
83
+ repo_path: absolute path to the repository root.
84
+ module: subdirectory name relative to repo_path (e.g. 'src/auth', 'api', 'core').
85
+ """
86
+ if not isinstance(repo_path, str):
87
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
88
+ if not isinstance(module, str) or not module.strip():
89
+ return _err("module must be a non-empty string", "INVALID_ARGUMENT")
90
+ module_path = os.path.join(repo_path, module)
91
+ return _execute([module_path, "--compact"])
92
+
93
+
94
+ @mcp.tool()
95
+ def get_delta(repo_path: str = ".", since: str = "HEAD~1") -> dict:
96
+ """Incremental context: git-changed files since a reference commit.
97
+
98
+ Maps to: sourcecode prepare-context delta <repo_path> --since <since>
99
+ repo_path: absolute path to the repository (default: current working directory).
100
+ since: git ref to diff against (e.g. HEAD~3, main, origin/main).
101
+ """
102
+ if not isinstance(repo_path, str):
103
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
104
+ if not isinstance(since, str) or not since.strip():
105
+ return _err("since must be a non-empty git ref", "INVALID_ARGUMENT")
106
+ return _execute(["prepare-context", "delta", repo_path, "--since", since])
107
+
108
+
109
+ @mcp.tool()
110
+ def get_ir_summary(repo_path: str = ".") -> dict:
111
+ """Deterministic symbol-level IR summary for Java repositories.
112
+
113
+ Maps to: sourcecode repo-ir <repo_path> --summary-only
114
+ Returns: analysis summary, impact, and change_set — omits full graph nodes/edges.
115
+ repo_path: absolute path to the repository (default: current working directory).
116
+ """
117
+ if not isinstance(repo_path, str):
118
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
119
+ return _execute(["repo-ir", repo_path, "--summary-only"])
@@ -13,12 +13,12 @@ def _invoke_result(exit_code: int = 0, output: str = "some output") -> MagicMock
13
13
  return m
14
14
 
15
15
 
16
- def test_run_command_returns_raw_string():
16
+ def test_run_command_parses_json():
17
17
  payload = '{"project": {"primary_stack": "python"}}'
18
18
  with patch("sourcecode.mcp.runner._runner.invoke", return_value=_invoke_result(0, payload)):
19
19
  result = run_command(["--agent"])
20
- assert isinstance(result, str)
21
- assert result == payload
20
+ assert isinstance(result, dict)
21
+ assert result == {"project": {"primary_stack": "python"}}
22
22
 
23
23
 
24
24
  def test_run_command_returns_non_json_string():
@@ -26,14 +26,6 @@ def test_mcp_serve_help():
26
26
  assert result.exit_code == 0
27
27
 
28
28
 
29
- def test_mcp_serve_missing_dependency_exits_with_hint():
30
- """ImportError on mcp package → exit 1 + install hint."""
31
- with patch.dict(sys.modules, {"sourcecode.mcp.server": None}):
32
- result = invoke(["mcp", "serve"])
33
- assert result.exit_code == 1
34
- assert "sourcecode[mcp]" in result.output
35
-
36
-
37
29
  def test_mcp_serve_calls_mcp_run():
38
30
  """When mcp is available, serve calls mcp.run()."""
39
31
  mock_server_mod = MagicMock()