sourcecode 1.31.20__tar.gz → 1.31.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.
- sourcecode-1.31.22/.continue-here.md +88 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/PKG-INFO +3 -3
- {sourcecode-1.31.20 → sourcecode-1.31.22}/README.md +2 -2
- {sourcecode-1.31.20 → sourcecode-1.31.22}/pyproject.toml +1 -1
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/ast_extractor.py +17 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/cli.py +66 -12
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/contract_pipeline.py +21 -1
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/server.py +26 -4
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/prepare_context.py +36 -2
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_audit_fixes.py +10 -3
- sourcecode-1.31.22/tests/test_bug_fixes_v1321.py +369 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_bug_fixes_v16.py +82 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_mcp_tools.py +47 -15
- sourcecode-1.31.20/.continue-here.md +0 -134
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.agents/skills/source-command-gsd-join-discord/SKILL.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.agents/skills/source-command-gsd-review-backlog/SKILL.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.agents/skills/source-command-gsd-workstreams/SKILL.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.gitignore +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.ruff.toml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/.sourcecode-cache/snapshot-3b5997a-fa5c742c.json +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/AUDIT_REAL_REPOS.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/CHANGELOG.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/CONTRIBUTING.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/LICENSE +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/SECURITY.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/docs/PRODUCT_TIERS.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/docs/privacy.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/docs/schema.md +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/raw +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/run_cli.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/cache.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/repository_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/__init__.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/conftest.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/coverage.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/fastapi_app/pyproject.toml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/fastapi_app/src/main.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/go_service/cmd/api/main.go +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/go_service/go.mod +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/jacoco.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/latin1_sample.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/latin1_sample_iso.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/lcov.info +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/nextjs_app/app/page.tsx +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/nextjs_app/package.json +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/nextjs_app/pnpm-lock.yaml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/pnpm_monorepo/apps/web/app/page.tsx +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/pnpm_monorepo/apps/web/package.json +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/pnpm_monorepo/packages/api/main.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/pnpm_monorepo/packages/api/pyproject.toml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/pnpm_monorepo/pnpm-workspace.yaml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/pom.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/application/service/FindAusenteService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/domain/entities/Ausente.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/ausente/infrastructure/rest/AusenteRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/application/service/FindAutocoberturasService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/domain/entities/Autocoberturas.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/autocoberturas/infrastructure/rest/AutocoberturasRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/application/service/FindCalendarioTrabajadorService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/domain/entities/CalendarioTrabajador.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/calendarioTrabajador/infrastructure/rest/CalendarioTrabajadorRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/application/service/FindDepartamentoService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/domain/entities/Departamento.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/departamento/infrastructure/rest/DepartamentoRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/application/service/FindEmpleadoService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/domain/entities/Empleado.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/ddd/empleado/infrastructure/rest/EmpleadoRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/DemoApplication.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/config/FilterConfig.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/domain/Health.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/mapper/HealthMapper.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/repository/HealthRepository.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/service/HealthService.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/HealthRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/java/com/example/demo/web/NominaRestController.java +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/resources/application-dev.yml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/resources/application.yml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/fixtures/spring_boot_minimal/src/main/resources/mapper/HealthMapper.xml +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_architecture_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_architecture_summary.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_ast_extractor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_audit_sas_v2.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_block1_reliability.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_block2_coverage.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_block5_quality.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_broadleaf_fixes.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_bug_fixes_v1302.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_bug_fixes_v13115.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_bug_fixes_v1312.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_bug_fixes_v1313.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_bug_fixes_v2.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_cache.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_canonical_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_classifier.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_cli.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_code_notes_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_context_scorer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_contract_pipeline.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_coverage_parser.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_cross_consistency.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_dependency_analyzer_node_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_dependency_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_dependency_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_dotnet.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_go_rust_java.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_nodejs.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_php_ruby_dart.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_universal_managed.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detector_universal_systems.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_detectors_base.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_doc_analyzer_jsdom.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_doc_analyzer_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_encoding_regression.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_enterprise_benchmarks.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_graph_analyzer_polyglot.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_graph_analyzer_python_node.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_graph_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_hybrid_inference.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_dependencies.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_detection.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_docs.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_graph_modules.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_lqn.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_metrics.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_multistack.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_semantics.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_integration_universal.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_java_spring_integration.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_mcp_runner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_mcp_serve.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_metrics_analyzer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_output_ux.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_packaging.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_phase1_improvements.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_pipeline_integrity.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_real_projects.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_redactor.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_repository_ir.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_scanner.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_schema_normalization.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_scoring_calibration.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_semantic_analyzer_node.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_semantic_analyzer_python.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_semantic_import_resolution.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_semantic_schema.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_signal_hierarchy.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_summarizer.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_surface_honesty.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_task_differentiation.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_telemetry.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_v131_improvements.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_v1_10_regressions.py +0 -0
- {sourcecode-1.31.20 → sourcecode-1.31.22}/tests/test_workspace_analyzer.py +0 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Handoff — sesión 23
|
|
2
|
+
**Date:** 2026-05-25T11:30:00Z
|
|
3
|
+
**Branch:** master
|
|
4
|
+
**Last commit:** `de61d65 fix(mcp): isError + changed-only always-include`
|
|
5
|
+
**Suite:** 59 pass (mcp_tools + mcp_serve + mcp_runner + bug_fixes_v16)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What was done this session
|
|
10
|
+
|
|
11
|
+
Two critical blocking bugs fixed, tested, committed.
|
|
12
|
+
|
|
13
|
+
### Bug 1 — MCP `isError` always false [FIXED]
|
|
14
|
+
|
|
15
|
+
**Root cause:** FastMCP serializes any plain `dict` return with `isError=false` regardless of content. `_err()` returned a dict → MCP spec §tool-result violated.
|
|
16
|
+
|
|
17
|
+
**Fix:**
|
|
18
|
+
- `_err()` now returns `CallToolResult(isError=True, content=[TextContent(json_payload)])` — passes through FastMCP unmodified
|
|
19
|
+
- `_execute()` also catches `success:false` in CLI JSON output → same `CallToolResult(isError=True)`
|
|
20
|
+
- All validation errors (`INVALID_ARGUMENT`) also get `isError=True`
|
|
21
|
+
|
|
22
|
+
**Files changed:**
|
|
23
|
+
| File | What |
|
|
24
|
+
|------|------|
|
|
25
|
+
| `src/sourcecode/mcp/server.py` | `_err()` returns `CallToolResult`; `_execute()` checks `success:false`; added `json`, `CallToolResult`, `TextContent` imports |
|
|
26
|
+
| `tests/test_mcp_tools.py` | `_assert_failure()` rewritten for `CallToolResult`; envelope tests updated; new test `test_get_impact_context_nonexistent_class_returns_is_error` |
|
|
27
|
+
|
|
28
|
+
### Bug 2 — `--changed-only` drops security const files [FIXED]
|
|
29
|
+
|
|
30
|
+
**Root cause:** `_resolve_java_constant()` needs const class files in `file_paths` to resolve `ClassName.FIELD_NAME` references in `@M3FiltroSeguridad` annotations. `--changed-only` filtered `sm.file_paths` to only git-changed files → const files absent → `resource_names_unresolved` 2→73.
|
|
31
|
+
|
|
32
|
+
**Fix:** "always-include" function `_is_always_include_ref(p)` added in two places:
|
|
33
|
+
- Criteria: name ends with `Const.java` / `Constants.java` OR path segment in `{security, seguridad, constantes}`
|
|
34
|
+
- Always-include files have `is_changed=False` (read-only anchors, not diff output)
|
|
35
|
+
|
|
36
|
+
**Files changed:**
|
|
37
|
+
| File | What |
|
|
38
|
+
|------|------|
|
|
39
|
+
| `src/sourcecode/contract_pipeline.py` | `changed_only` filter uses `_is_always_include_ref()` |
|
|
40
|
+
| `src/sourcecode/cli.py` | `sm.file_paths` filter in compact mode uses `_is_always_include_ref()` |
|
|
41
|
+
| `tests/test_bug_fixes_v16.py` | New: `test_contract_pipeline_changed_only_always_includes_const_files` + `test_changed_only_resource_names_unresolved_le5` |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Current state
|
|
46
|
+
|
|
47
|
+
Working tree **clean** — 2 untracked files pending decision:
|
|
48
|
+
- `AUDIT_REAL_REPOS.md` — full adversarial audit findings (Keycloak + Broadleaf)
|
|
49
|
+
- `docs/PRODUCT_TIERS.md` — product tiers doc
|
|
50
|
+
|
|
51
|
+
GSD state: milestone v1.0, 13 phases all complete (100%).
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## P1 bugs remaining (from AUDIT_REAL_REPOS.md)
|
|
56
|
+
|
|
57
|
+
- **BUG-P1-01** Risk score inconsistency: same 0-callers → different risk_level depending on heuristic
|
|
58
|
+
- **BUG-P1-02** `project_summary` copies README blurb instead of generating from code structure
|
|
59
|
+
- **BUG-P1-03** `fix-bug` returns 426 files for generic NPE — no score field, no cap
|
|
60
|
+
- **BUG-P1-04** `indirect_callers: 0` for KeycloakSession (1992 direct callers) — BFS exhausts at depth 1
|
|
61
|
+
|
|
62
|
+
## P2 bugs remaining
|
|
63
|
+
|
|
64
|
+
- BUG-P2-01 `bounded_contexts` uses utility packages, not Maven modules
|
|
65
|
+
- BUG-P2-02 `role: unknown` for all modernize `high_coupling_nodes`
|
|
66
|
+
- BUG-P2-03 `no_security_signal` always 100% for filter-based security (JAX-RS/XML)
|
|
67
|
+
- BUG-P2-04 JAX-RS sub-resource paths not composed with parent `@Path`
|
|
68
|
+
- BUG-P2-05 Broadleaf admin paths mixed into REST endpoints
|
|
69
|
+
- BUG-P2-06 Architecture confidence inconsistent `--compact` vs `--agent`
|
|
70
|
+
- BUG-P2-07 `entry_points.controllers.methods: 21` vs endpoints 130
|
|
71
|
+
- BUG-P2-08 `--format`/`--no-cache` inconsistently available across subcommands
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Next session: where to start
|
|
76
|
+
|
|
77
|
+
**Recommended: BUG-P1-01** — risk score consistency (0 callers → uniform risk_level). Short fix, visible correctness.
|
|
78
|
+
|
|
79
|
+
Then: BUG-P1-04 (BFS depth cap for large fan-in) or BUG-P1-02 (project_summary from code).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Resume
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
cat .continue-here.md
|
|
87
|
+
python3 -m pytest tests/ -q --tb=short 2>&1 | tail -5
|
|
88
|
+
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.31.
|
|
3
|
+
Version: 1.31.22
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -225,7 +225,7 @@ Description-Content-Type: text/markdown
|
|
|
225
225
|
|
|
226
226
|
**AI-ready change intelligence for Java/Spring enterprise monoliths.**
|
|
227
227
|
|
|
228
|
-

|
|
229
229
|

|
|
230
230
|
|
|
231
231
|
---
|
|
@@ -263,7 +263,7 @@ pipx install sourcecode
|
|
|
263
263
|
|
|
264
264
|
```bash
|
|
265
265
|
sourcecode version
|
|
266
|
-
# sourcecode 1.31.
|
|
266
|
+
# sourcecode 1.31.22
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
---
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**AI-ready change intelligence for Java/Spring enterprise monoliths.**
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|

|
|
7
7
|
|
|
8
8
|
---
|
|
@@ -40,7 +40,7 @@ pipx install sourcecode
|
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
sourcecode version
|
|
43
|
-
# sourcecode 1.31.
|
|
43
|
+
# sourcecode 1.31.22
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
---
|
|
@@ -1131,6 +1131,23 @@ def _detect_role(path: str, contract: FileContract) -> str:
|
|
|
1131
1131
|
if any(n.startswith("use") and len(n) > 3 and n[3:4].isupper() for n in export_names):
|
|
1132
1132
|
return "hook"
|
|
1133
1133
|
|
|
1134
|
+
# Angular-specific roles (.ts files): detect by stem suffix before generic checks.
|
|
1135
|
+
# Must run before the "service" path-keyword check to prevent misclassification.
|
|
1136
|
+
if ext == ".ts":
|
|
1137
|
+
_ts_last = Path(path).stem.lower().rsplit(".", 1)[-1]
|
|
1138
|
+
_NG_ROLE_MAP = {
|
|
1139
|
+
"component": "component",
|
|
1140
|
+
"pipe": "pipe",
|
|
1141
|
+
"directive": "directive",
|
|
1142
|
+
"guard": "guard",
|
|
1143
|
+
"interceptor": "interceptor",
|
|
1144
|
+
"resolver": "resolver",
|
|
1145
|
+
"module": "module",
|
|
1146
|
+
"service": "service",
|
|
1147
|
+
}
|
|
1148
|
+
if _ts_last in _NG_ROLE_MAP:
|
|
1149
|
+
return _NG_ROLE_MAP[_ts_last]
|
|
1150
|
+
|
|
1134
1151
|
# Route / page
|
|
1135
1152
|
if any(x in path_lower for x in ["/routes/", "/route.", "/pages/", "/api/", "/handlers/"]):
|
|
1136
1153
|
return "route"
|
|
@@ -238,6 +238,21 @@ def _preprocess_argv() -> None:
|
|
|
238
238
|
_sys.argv = _sys.argv[:1] + modified
|
|
239
239
|
|
|
240
240
|
|
|
241
|
+
def _emit_error_json(error: str, message: str, **context: object) -> None:
|
|
242
|
+
"""Write a structured JSON error envelope to stderr.
|
|
243
|
+
|
|
244
|
+
Format: {"error": "<code>", "message": "<human text>", ...<context>}
|
|
245
|
+
All CLI validation and runtime errors must go through this helper so that
|
|
246
|
+
agents and tools can parse stderr reliably regardless of error type.
|
|
247
|
+
"""
|
|
248
|
+
import json as _json
|
|
249
|
+
import sys as _sys
|
|
250
|
+
payload: dict[str, object] = {"error": error, "message": message}
|
|
251
|
+
payload.update(context)
|
|
252
|
+
_sys.stderr.write(_json.dumps(payload, ensure_ascii=False) + "\n")
|
|
253
|
+
_sys.stderr.flush()
|
|
254
|
+
|
|
255
|
+
|
|
241
256
|
def _copy_to_clipboard(content: str) -> bool:
|
|
242
257
|
"""Copy text to system clipboard. Returns True on success, False otherwise (never raises)."""
|
|
243
258
|
import subprocess
|
|
@@ -751,21 +766,30 @@ def main(
|
|
|
751
766
|
|
|
752
767
|
# Validate format choices
|
|
753
768
|
if format not in FORMAT_CHOICES:
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
769
|
+
_emit_error_json(
|
|
770
|
+
"invalid_flag_value",
|
|
771
|
+
f"Invalid value '{format}' for --format. Valid values: {', '.join(FORMAT_CHOICES)}.",
|
|
772
|
+
flag="--format",
|
|
773
|
+
value=format,
|
|
774
|
+
valid_values=list(FORMAT_CHOICES),
|
|
757
775
|
)
|
|
758
776
|
raise typer.Exit(code=2) # FIX-P2-7: arg validation → exit 2
|
|
759
777
|
if graph_detail not in GRAPH_DETAIL_CHOICES:
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
778
|
+
_emit_error_json(
|
|
779
|
+
"invalid_flag_value",
|
|
780
|
+
f"Invalid value '{graph_detail}' for --graph-detail. Valid values: {', '.join(GRAPH_DETAIL_CHOICES)}.",
|
|
781
|
+
flag="--graph-detail",
|
|
782
|
+
value=graph_detail,
|
|
783
|
+
valid_values=list(GRAPH_DETAIL_CHOICES),
|
|
763
784
|
)
|
|
764
785
|
raise typer.Exit(code=2) # FIX-P2-7: arg validation → exit 2
|
|
765
786
|
if docs_depth not in DOCS_DEPTH_CHOICES:
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
787
|
+
_emit_error_json(
|
|
788
|
+
"invalid_flag_value",
|
|
789
|
+
f"Invalid value '{docs_depth}' for --docs-depth. Valid values: {', '.join(DOCS_DEPTH_CHOICES)}.",
|
|
790
|
+
flag="--docs-depth",
|
|
791
|
+
value=docs_depth,
|
|
792
|
+
valid_values=list(DOCS_DEPTH_CHOICES),
|
|
769
793
|
)
|
|
770
794
|
raise typer.Exit(code=2) # FIX-P2-7: arg validation → exit 2
|
|
771
795
|
|
|
@@ -775,10 +799,18 @@ def main(
|
|
|
775
799
|
_raw_path_input = _detected_path[0]
|
|
776
800
|
target = Path(_raw_path_input).resolve()
|
|
777
801
|
if not target.exists():
|
|
778
|
-
|
|
802
|
+
_emit_error_json(
|
|
803
|
+
"directory_not_found",
|
|
804
|
+
f"Directory '{_raw_path_input}' does not exist.",
|
|
805
|
+
path=_raw_path_input,
|
|
806
|
+
)
|
|
779
807
|
raise typer.Exit(code=1)
|
|
780
808
|
if not target.is_dir():
|
|
781
|
-
|
|
809
|
+
_emit_error_json(
|
|
810
|
+
"not_a_directory",
|
|
811
|
+
f"Path '{_raw_path_input}' is not a directory.",
|
|
812
|
+
path=_raw_path_input,
|
|
813
|
+
)
|
|
782
814
|
raise typer.Exit(code=1)
|
|
783
815
|
|
|
784
816
|
# Normalize mode aliases
|
|
@@ -1201,6 +1233,15 @@ def main(
|
|
|
1201
1233
|
workspace_root = target / workspace.path
|
|
1202
1234
|
if not workspace_root.exists() or not workspace_root.is_dir():
|
|
1203
1235
|
continue
|
|
1236
|
+
# BUG-2: skip workspaces explicitly excluded via --exclude.
|
|
1237
|
+
# Without this guard, excluded frontend/backend modules still contribute
|
|
1238
|
+
# their stacks and entry_points, causing architecture_summary to describe
|
|
1239
|
+
# stacks that were intentionally filtered out.
|
|
1240
|
+
if _extra_excludes:
|
|
1241
|
+
_ws_norm = workspace.path.replace("\\", "/").strip("/")
|
|
1242
|
+
_ws_parts = frozenset(_ws_norm.split("/"))
|
|
1243
|
+
if _ws_parts & _extra_excludes:
|
|
1244
|
+
continue
|
|
1204
1245
|
_ws_topology = RepoClassifier().classify(workspace_root)
|
|
1205
1246
|
workspace_scanner = AdaptiveScanner(workspace_root, topology=_ws_topology, base_depth=depth)
|
|
1206
1247
|
workspace_tree = filter_sensitive_files(workspace_scanner.scan_tree())
|
|
@@ -1776,8 +1817,21 @@ def main(
|
|
|
1776
1817
|
if changed_only and _allowed_changed_files:
|
|
1777
1818
|
# GAP-5: preserve full entry_points for architecture context even in
|
|
1778
1819
|
# --changed-only mode. Only filter file_paths and code_notes.
|
|
1820
|
+
# ALWAYS-INCLUDE: security-const files must stay in file_paths even when
|
|
1821
|
+
# not in the git diff — they resolve Java constant references used in
|
|
1822
|
+
# @M3FiltroSeguridad annotations (read-only anchors, not diff output).
|
|
1823
|
+
def _is_always_include_ref(p: str) -> bool:
|
|
1824
|
+
name = p.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
|
|
1825
|
+
if name.endswith("Const.java") or name.endswith("Constants.java"):
|
|
1826
|
+
return True
|
|
1827
|
+
parts = p.replace("\\", "/").lower().split("/")
|
|
1828
|
+
return any(seg in ("security", "seguridad", "constantes") for seg in parts)
|
|
1829
|
+
|
|
1779
1830
|
sm = _replace(sm,
|
|
1780
|
-
file_paths=[
|
|
1831
|
+
file_paths=[
|
|
1832
|
+
p for p in sm.file_paths
|
|
1833
|
+
if p in _allowed_changed_files or _is_always_include_ref(p)
|
|
1834
|
+
],
|
|
1781
1835
|
code_notes=[n for n in sm.code_notes if n.path in _allowed_changed_files],
|
|
1782
1836
|
)
|
|
1783
1837
|
data = compact_view(sm, no_tree=no_tree, full=full)
|
|
@@ -242,7 +242,27 @@ class ContractPipeline:
|
|
|
242
242
|
]
|
|
243
243
|
|
|
244
244
|
if changed_only:
|
|
245
|
-
|
|
245
|
+
def _is_always_include_ref(p: str) -> bool:
|
|
246
|
+
"""Always include security-const files regardless of diff status.
|
|
247
|
+
|
|
248
|
+
These are read-only reference anchors: they resolve Java constant
|
|
249
|
+
references (e.g. SeguridadRecursosConst.REC_X) used in security
|
|
250
|
+
annotations. They do NOT appear in diff output because
|
|
251
|
+
contract.is_changed is set from ``changed_files`` only (line below).
|
|
252
|
+
Criteria per bug-spec:
|
|
253
|
+
- name ends with Const.java or Constants.java
|
|
254
|
+
- any path segment is: security | seguridad | constantes
|
|
255
|
+
"""
|
|
256
|
+
name = p.rsplit("/", 1)[-1].rsplit("\\", 1)[-1]
|
|
257
|
+
if name.endswith("Const.java") or name.endswith("Constants.java"):
|
|
258
|
+
return True
|
|
259
|
+
parts = p.replace("\\", "/").lower().split("/")
|
|
260
|
+
return any(seg in ("security", "seguridad", "constantes") for seg in parts)
|
|
261
|
+
|
|
262
|
+
src_paths = [
|
|
263
|
+
p for p in src_paths
|
|
264
|
+
if p in changed_files or _is_always_include_ref(p)
|
|
265
|
+
]
|
|
246
266
|
|
|
247
267
|
# Apply max_files cap — bypass when symbol search to ensure defining files are found.
|
|
248
268
|
# A symbol query over a large repo needs all files; result set is small after filtering.
|
|
@@ -10,10 +10,12 @@ data is the parsed JSON object from the CLI output, not a shell string.
|
|
|
10
10
|
"""
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
|
+
import json
|
|
13
14
|
import os
|
|
14
15
|
from typing import Any
|
|
15
16
|
|
|
16
17
|
from mcp.server.fastmcp import FastMCP
|
|
18
|
+
from mcp.types import CallToolResult, TextContent
|
|
17
19
|
|
|
18
20
|
from sourcecode import __version__ as _sourcecode_version
|
|
19
21
|
from sourcecode.mcp.runner import run_command
|
|
@@ -30,15 +32,35 @@ def _ok(data: Any) -> dict:
|
|
|
30
32
|
return {"success": True, "data": data, "error": None}
|
|
31
33
|
|
|
32
34
|
|
|
33
|
-
def _err(message: str, code: str = "EXECUTION_FAILED") ->
|
|
34
|
-
|
|
35
|
+
def _err(message: str, code: str = "EXECUTION_FAILED") -> CallToolResult:
|
|
36
|
+
"""Return an MCP tool-error result with isError=True per MCP spec §tool-result."""
|
|
37
|
+
payload = {"success": False, "data": None, "error": {"code": code, "message": message}}
|
|
38
|
+
return CallToolResult(
|
|
39
|
+
content=[TextContent(type="text", text=json.dumps(payload))],
|
|
40
|
+
isError=True,
|
|
41
|
+
)
|
|
35
42
|
|
|
36
43
|
|
|
37
|
-
def _execute(args: list[str]) -> dict:
|
|
44
|
+
def _execute(args: list[str]) -> dict | CallToolResult:
|
|
38
45
|
try:
|
|
39
|
-
|
|
46
|
+
result = run_command(args)
|
|
40
47
|
except RuntimeError as exc:
|
|
41
48
|
return _err(str(exc))
|
|
49
|
+
# If CLI output itself signals failure via success:false, propagate as isError=True
|
|
50
|
+
if isinstance(result, dict) and result.get("success") is False:
|
|
51
|
+
payload = {
|
|
52
|
+
"success": False,
|
|
53
|
+
"data": None,
|
|
54
|
+
"error": result.get("error") or {
|
|
55
|
+
"code": "EXECUTION_FAILED",
|
|
56
|
+
"message": "Command returned success=false",
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
return CallToolResult(
|
|
60
|
+
content=[TextContent(type="text", text=json.dumps(payload))],
|
|
61
|
+
isError=True,
|
|
62
|
+
)
|
|
63
|
+
return _ok(result)
|
|
42
64
|
|
|
43
65
|
|
|
44
66
|
@mcp.tool()
|
|
@@ -589,6 +589,15 @@ _ARTIFACT_CHANGE_EFFECT: dict[str, str] = {
|
|
|
589
589
|
"documentation": "documentation file (no runtime impact)",
|
|
590
590
|
"ide_noise": "IDE/tooling artifact (no application impact)",
|
|
591
591
|
"source": "application source file (role could not be confirmed from code signals)",
|
|
592
|
+
# Angular-specific artifact types (detected before Java/Spring heuristics)
|
|
593
|
+
"ng_component": "UI presentation layer (Angular @Component)",
|
|
594
|
+
"ng_pipe": "data transformation layer (Angular @Pipe)",
|
|
595
|
+
"ng_directive": "DOM behavior layer (Angular @Directive)",
|
|
596
|
+
"ng_guard": "navigation guard (Angular CanActivate / CanActivateFn)",
|
|
597
|
+
"ng_interceptor": "HTTP middleware layer (Angular HttpInterceptor)",
|
|
598
|
+
"ng_resolver": "data pre-fetch layer (Angular Resolve)",
|
|
599
|
+
"ng_service": "Angular injectable service (@Injectable)",
|
|
600
|
+
"ng_module": "Angular feature module (@NgModule)",
|
|
592
601
|
}
|
|
593
602
|
|
|
594
603
|
# Maps frontend symptom keywords → backend terms likely to contain the root cause.
|
|
@@ -2710,6 +2719,29 @@ class TaskContextBuilder:
|
|
|
2710
2719
|
):
|
|
2711
2720
|
return {"artifact_type": "entrypoint", "risk_areas": ["api", "config"], "impact_level": "critical", "is_noise": False, "module": module, "confidence": "high"}
|
|
2712
2721
|
|
|
2722
|
+
# Angular-specific artifact detection (.ts files only).
|
|
2723
|
+
# Must run BEFORE the Java/Spring heuristics so that *.component.ts,
|
|
2724
|
+
# *.pipe.ts, etc. are never misclassified as "service" or "security".
|
|
2725
|
+
# Detection is pure-path/stem — no file reads, fully deterministic.
|
|
2726
|
+
if suffix == ".ts":
|
|
2727
|
+
# Stem may be multi-part: "causa-denegacion-form.component" → last part is the Angular type
|
|
2728
|
+
_ts_last = stem_lower.rsplit(".", 1)[-1] # "component", "pipe", etc.
|
|
2729
|
+
_NG_SUFFIX_MAP = {
|
|
2730
|
+
"component": ("ng_component", ["ui"], "medium"),
|
|
2731
|
+
"pipe": ("ng_pipe", ["ui"], "low"),
|
|
2732
|
+
"directive": ("ng_directive", ["ui"], "medium"),
|
|
2733
|
+
"guard": ("ng_guard", ["security", "auth"], "high"),
|
|
2734
|
+
"interceptor": ("ng_interceptor", ["api"], "medium"),
|
|
2735
|
+
"resolver": ("ng_resolver", ["api"], "low"),
|
|
2736
|
+
"module": ("ng_module", ["config"], "medium"),
|
|
2737
|
+
}
|
|
2738
|
+
if _ts_last in _NG_SUFFIX_MAP:
|
|
2739
|
+
_ng_atype, _ng_risks, _ng_impact = _NG_SUFFIX_MAP[_ts_last]
|
|
2740
|
+
return {"artifact_type": _ng_atype, "risk_areas": _ng_risks, "impact_level": _ng_impact, "is_noise": False, "module": module, "confidence": "high"}
|
|
2741
|
+
# Angular service: stem ends with ".service" or equals "service"
|
|
2742
|
+
if _ts_last == "service":
|
|
2743
|
+
return {"artifact_type": "ng_service", "risk_areas": ["business_logic"], "impact_level": "medium", "is_noise": False, "module": module, "confidence": "high"}
|
|
2744
|
+
|
|
2713
2745
|
# Security surface (extended: interceptor, filter, cors, acl)
|
|
2714
2746
|
_SECURITY_KW = ("security", "auth", "jwt", "token", "permission", "role",
|
|
2715
2747
|
"credential", "encrypt", "decrypt", "oauth", "saml", "ldap",
|
|
@@ -2724,9 +2756,11 @@ class TaskContextBuilder:
|
|
|
2724
2756
|
if suffix in _CODE_EXTS and any(kw in stem_lower for kw in _API_KW):
|
|
2725
2757
|
return {"artifact_type": "controller", "risk_areas": ["api"], "impact_level": "high", "is_noise": False, "module": module, "confidence": "high"}
|
|
2726
2758
|
|
|
2727
|
-
# Business logic / services (extended: facade, usecase, aspect, listener
|
|
2759
|
+
# Business logic / services (extended: facade, usecase, aspect, listener)
|
|
2760
|
+
# NOTE: "component" intentionally removed — Angular *.component.ts files
|
|
2761
|
+
# are caught above by the Angular-specific block before reaching here.
|
|
2728
2762
|
_SERVICE_KW = ("service", "serviceimpl", "servicefacade", "facade", "usecase",
|
|
2729
|
-
"interactor", "aspect", "listener", "subscriber", "eventhandler"
|
|
2763
|
+
"interactor", "aspect", "listener", "subscriber", "eventhandler")
|
|
2730
2764
|
if suffix in _CODE_EXTS and any(kw in stem_lower for kw in _SERVICE_KW):
|
|
2731
2765
|
return {"artifact_type": "service", "risk_areas": ["transactions", "business_logic"], "impact_level": "high", "is_noise": False, "module": module, "confidence": "high"}
|
|
2732
2766
|
|
|
@@ -814,12 +814,19 @@ class TestTelemetrySchema:
|
|
|
814
814
|
)
|
|
815
815
|
|
|
816
816
|
def test_telemetry_invalid_action_returns_error_with_valid_list(self):
|
|
817
|
+
import json
|
|
818
|
+
from mcp.types import CallToolResult
|
|
817
819
|
from sourcecode.mcp.server import telemetry
|
|
818
820
|
result = telemetry("unknown_action")
|
|
819
|
-
assert result
|
|
820
|
-
|
|
821
|
+
assert isinstance(result, CallToolResult), (
|
|
822
|
+
f"expected CallToolResult, got {type(result).__name__}"
|
|
823
|
+
)
|
|
824
|
+
assert result.isError is True, "isError must be True for tool failures"
|
|
825
|
+
payload = json.loads(result.content[0].text)
|
|
826
|
+
assert payload["success"] is False
|
|
827
|
+
assert payload["error"] is not None
|
|
821
828
|
# Error message must enumerate valid actions
|
|
822
|
-
msg =
|
|
829
|
+
msg = payload["error"]["message"]
|
|
823
830
|
for action in ("status", "enable", "disable"):
|
|
824
831
|
assert action in msg, (
|
|
825
832
|
f"telemetry error message must list valid action '{action}': {msg!r}"
|