sourcecode 1.35.19__tar.gz → 1.35.20__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 (107) hide show
  1. {sourcecode-1.35.19 → sourcecode-1.35.20}/PKG-INFO +3 -3
  2. {sourcecode-1.35.19 → sourcecode-1.35.20}/README.md +2 -2
  3. {sourcecode-1.35.19 → sourcecode-1.35.20}/pyproject.toml +1 -1
  4. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/__init__.py +1 -1
  5. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/cli.py +108 -5
  6. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/registry.py +52 -1
  7. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/server.py +50 -0
  8. {sourcecode-1.35.19 → sourcecode-1.35.20}/.github/workflows/build-windows.yml +0 -0
  9. {sourcecode-1.35.19 → sourcecode-1.35.20}/.gitignore +0 -0
  10. {sourcecode-1.35.19 → sourcecode-1.35.20}/.ruff.toml +0 -0
  11. {sourcecode-1.35.19 → sourcecode-1.35.20}/CHANGELOG.md +0 -0
  12. {sourcecode-1.35.19 → sourcecode-1.35.20}/CONTRIBUTING.md +0 -0
  13. {sourcecode-1.35.19 → sourcecode-1.35.20}/LICENSE +0 -0
  14. {sourcecode-1.35.19 → sourcecode-1.35.20}/SECURITY.md +0 -0
  15. {sourcecode-1.35.19 → sourcecode-1.35.20}/raw +0 -0
  16. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/adaptive_scanner.py +0 -0
  17. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/architecture_analyzer.py +0 -0
  18. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/architecture_summary.py +0 -0
  19. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/ast_extractor.py +0 -0
  20. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/cache.py +0 -0
  21. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/canonical_ir.py +0 -0
  22. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/cir_graphs.py +0 -0
  23. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/classifier.py +0 -0
  24. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/code_notes_analyzer.py +0 -0
  25. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/confidence_analyzer.py +0 -0
  26. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/context_scorer.py +0 -0
  27. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/context_summarizer.py +0 -0
  28. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/contract_model.py +0 -0
  29. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/contract_pipeline.py +0 -0
  30. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/coverage_parser.py +0 -0
  31. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/dependency_analyzer.py +0 -0
  32. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/__init__.py +0 -0
  33. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/base.py +0 -0
  34. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/csproj_parser.py +0 -0
  35. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/dart.py +0 -0
  36. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/dotnet.py +0 -0
  37. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/elixir.py +0 -0
  38. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/go.py +0 -0
  39. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/heuristic.py +0 -0
  40. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/hybrid.py +0 -0
  41. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/java.py +0 -0
  42. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/jvm_ext.py +0 -0
  43. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/nodejs.py +0 -0
  44. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/parsers.py +0 -0
  45. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/php.py +0 -0
  46. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/project.py +0 -0
  47. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/python.py +0 -0
  48. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/ruby.py +0 -0
  49. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/rust.py +0 -0
  50. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/systems.py +0 -0
  51. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/terraform.py +0 -0
  52. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/detectors/tooling.py +0 -0
  53. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/doc_analyzer.py +0 -0
  54. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/entrypoint_classifier.py +0 -0
  55. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/env_analyzer.py +0 -0
  56. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/error_schema.py +0 -0
  57. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/explain.py +0 -0
  58. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/file_classifier.py +0 -0
  59. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/flow_analyzer.py +0 -0
  60. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/fqn_utils.py +0 -0
  61. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/git_analyzer.py +0 -0
  62. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/graph_analyzer.py +0 -0
  63. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/license.py +0 -0
  64. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/__init__.py +0 -0
  65. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
  66. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/onboarding/applier.py +0 -0
  67. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/onboarding/backup.py +0 -0
  68. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/onboarding/detector.py +0 -0
  69. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/onboarding/planner.py +0 -0
  70. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/orchestrator.py +0 -0
  71. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp/runner.py +0 -0
  72. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/mcp_nudge.py +0 -0
  73. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/metrics_analyzer.py +0 -0
  74. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/migrate_check.py +0 -0
  75. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/output_budget.py +0 -0
  76. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/path_filters.py +0 -0
  77. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/pr_comment_renderer.py +0 -0
  78. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/pr_impact.py +0 -0
  79. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/prepare_context.py +0 -0
  80. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/progress.py +0 -0
  81. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/ranking_engine.py +0 -0
  82. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/redactor.py +0 -0
  83. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/relevance_scorer.py +0 -0
  84. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/repo_classifier.py +0 -0
  85. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/repository_ir.py +0 -0
  86. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/ris.py +0 -0
  87. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/runtime_classifier.py +0 -0
  88. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/scanner.py +0 -0
  89. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/schema.py +0 -0
  90. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/semantic_analyzer.py +0 -0
  91. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/serializer.py +0 -0
  92. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_event_topology.py +0 -0
  93. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_findings.py +0 -0
  94. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_impact.py +0 -0
  95. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_model.py +0 -0
  96. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_security_audit.py +0 -0
  97. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_semantic.py +0 -0
  98. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/spring_tx_analyzer.py +0 -0
  99. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/summarizer.py +0 -0
  100. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/telemetry/__init__.py +0 -0
  101. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/telemetry/config.py +0 -0
  102. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/telemetry/consent.py +0 -0
  103. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/telemetry/events.py +0 -0
  104. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/telemetry/filters.py +0 -0
  105. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/telemetry/transport.py +0 -0
  106. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/tree_utils.py +0 -0
  107. {sourcecode-1.35.19 → sourcecode-1.35.20}/src/sourcecode/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 1.35.19
3
+ Version: 1.35.20
4
4
  Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
5
5
  License-File: LICENSE
6
6
  Keywords: agents,ai,codebase,context,developer-tools,llm
@@ -40,7 +40,7 @@ Description-Content-Type: text/markdown
40
40
 
41
41
  **Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
42
42
 
43
- ![Version](https://img.shields.io/badge/version-1.35.16-blue)
43
+ ![Version](https://img.shields.io/badge/version-1.35.20-blue)
44
44
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
45
45
 
46
46
  ---
@@ -114,7 +114,7 @@ pipx install sourcecode
114
114
 
115
115
  ```bash
116
116
  sourcecode version
117
- # sourcecode 1.35.16
117
+ # sourcecode 1.35.20
118
118
  ```
119
119
 
120
120
  ---
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
4
4
 
5
- ![Version](https://img.shields.io/badge/version-1.35.16-blue)
5
+ ![Version](https://img.shields.io/badge/version-1.35.20-blue)
6
6
  ![Python](https://img.shields.io/badge/python-3.10%2B-green)
7
7
 
8
8
  ---
@@ -76,7 +76,7 @@ pipx install sourcecode
76
76
 
77
77
  ```bash
78
78
  sourcecode version
79
- # sourcecode 1.35.16
79
+ # sourcecode 1.35.20
80
80
  ```
81
81
 
82
82
  ---
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "sourcecode"
7
- version = "1.35.19"
7
+ version = "1.35.20"
8
8
  description = "Persistent structural context and ultra-fast repeated analysis 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.35.19"
3
+ __version__ = "1.35.20"
@@ -3722,6 +3722,80 @@ def endpoints_cmd(
3722
3722
 
3723
3723
  # ── Spring Semantic Audit ─────────────────────────────────────────────────────
3724
3724
 
3725
+
3726
+ def _render_spring_audit_github_comment(result: "SpringAuditResult", min_severity: str = "low") -> str: # type: ignore[name-defined]
3727
+ """Render SpringAuditResult as a GitHub PR comment in Markdown."""
3728
+ from sourcecode.spring_findings import SEVERITY_ORDER
3729
+
3730
+ min_order = SEVERITY_ORDER.get(min_severity, 3)
3731
+ visible = [f for f in result.findings if SEVERITY_ORDER.get(f.severity, 3) <= min_order]
3732
+
3733
+ sev = result.summary.get("by_severity", {})
3734
+ total = result.summary.get("total_findings", 0)
3735
+ blocking = sev.get("critical", 0) + sev.get("high", 0)
3736
+
3737
+ _ICONS = {"critical": "🔴", "high": "🟠", "medium": "🟡", "low": "🔵"}
3738
+ _LABELS = {"critical": "CRITICAL", "high": "HIGH", "medium": "MEDIUM", "low": "LOW"}
3739
+
3740
+ if total == 0:
3741
+ status_line = "✅ **Spring Audit — no findings**"
3742
+ elif blocking > 0:
3743
+ status_line = f"🔴 **Spring Audit — {total} finding{'s' if total != 1 else ''} ({blocking} blocking)**"
3744
+ else:
3745
+ status_line = f"🟡 **Spring Audit — {total} finding{'s' if total != 1 else ''} (0 blocking)**"
3746
+
3747
+ lines: list[str] = [status_line, ""]
3748
+
3749
+ if total > 0:
3750
+ severity_counts = []
3751
+ for sev_name in ("critical", "high", "medium", "low"):
3752
+ n = sev.get(sev_name, 0)
3753
+ if n:
3754
+ severity_counts.append(f"{_ICONS[sev_name]} {n} {sev_name}")
3755
+ lines.append("**Severity:** " + " · ".join(severity_counts))
3756
+ lines.append("")
3757
+
3758
+ if not visible:
3759
+ lines.append(f"_No findings at or above `{min_severity}` severity._")
3760
+ return "\n".join(lines)
3761
+
3762
+ lines += [
3763
+ "| Sev | Pattern | File | Symbol | Title |",
3764
+ "|-----|---------|------|--------|-------|",
3765
+ ]
3766
+ for f in sorted(visible, key=lambda x: (SEVERITY_ORDER.get(x.severity, 3), x.source_file)):
3767
+ icon = _ICONS.get(f.severity, "")
3768
+ label = _LABELS.get(f.severity, f.severity.upper())
3769
+ short_file = f.source_file.split("/")[-1] if "/" in f.source_file else f.source_file
3770
+ short_sym = f.symbol.split(".")[-1] if "." in f.symbol else f.symbol
3771
+ title_escaped = f.title.replace("|", "\\|")
3772
+ lines.append(f"| {icon} {label} | `{f.pattern_id}` | `{short_file}` | `{short_sym}` | {title_escaped} |")
3773
+
3774
+ lines.append("")
3775
+
3776
+ if visible:
3777
+ lines.append("<details>")
3778
+ lines.append("<summary>Finding details</summary>")
3779
+ lines.append("")
3780
+ for f in sorted(visible, key=lambda x: (SEVERITY_ORDER.get(x.severity, 3), x.source_file)):
3781
+ icon = _ICONS.get(f.severity, "")
3782
+ lines.append(f"### {icon} `{f.pattern_id}` — {f.title}")
3783
+ lines.append(f"**File:** `{f.source_file}` **Symbol:** `{f.symbol}`")
3784
+ lines.append("")
3785
+ lines.append(f.explanation)
3786
+ lines.append("")
3787
+ lines.append(f"**Fix:** {f.fix_hint}")
3788
+ lines.append("")
3789
+ lines.append("</details>")
3790
+
3791
+ lines += [
3792
+ "",
3793
+ f"_Generated by [sourcecode](https://github.com/sourcecode-ai/sourcecode) · "
3794
+ f"scope: {result.scope} · min-severity: {min_severity}_",
3795
+ ]
3796
+ return "\n".join(lines)
3797
+
3798
+
3725
3799
  @app.command("spring-audit")
3726
3800
  def spring_audit_cmd(
3727
3801
  path: Path = typer.Argument(
@@ -3736,7 +3810,7 @@ def spring_audit_cmd(
3736
3810
  "json",
3737
3811
  "--format",
3738
3812
  "-f",
3739
- help="Output format: json (default) or yaml.",
3813
+ help="Output format: json (default), yaml, or github-comment.",
3740
3814
  show_default=True,
3741
3815
  ),
3742
3816
  copy: bool = typer.Option(
@@ -3758,6 +3832,11 @@ def spring_audit_cmd(
3758
3832
  help="Minimum severity to include: critical, high, medium, or low (default).",
3759
3833
  show_default=True,
3760
3834
  ),
3835
+ ci: bool = typer.Option(
3836
+ False,
3837
+ "--ci/--no-ci",
3838
+ help="Exit with code 1 if any findings at or above --min-severity are found. For CI/CD gates.",
3839
+ ),
3761
3840
  ) -> None:
3762
3841
  """Spring semantic audit: TX anomalies (TX-001..005) + security surface (SEC-001..003).
3763
3842
 
@@ -3772,6 +3851,12 @@ def spring_audit_cmd(
3772
3851
  SEC-002 CVE-2025-41248: @PreAuthorize on inherited method from generic supertype
3773
3852
  SEC-003 @Transactional on @Controller/@RestController (TX in wrong layer)
3774
3853
 
3854
+ \b
3855
+ CI/CD usage:
3856
+ sourcecode spring-audit . --ci # exit 1 on any finding
3857
+ sourcecode spring-audit . --ci --min-severity high # exit 1 only on high/critical
3858
+ sourcecode spring-audit . --ci --format github-comment # Markdown PR comment + exit 1
3859
+
3775
3860
  \b
3776
3861
  Examples:
3777
3862
  sourcecode spring-audit .
@@ -3818,15 +3903,27 @@ def spring_audit_cmd(
3818
3903
  )
3819
3904
  raise typer.Exit(code=1)
3820
3905
 
3906
+ if format not in ("json", "yaml", "github-comment"):
3907
+ _emit_error_json(
3908
+ INVALID_INPUT_CODE,
3909
+ f"Invalid format '{format}'.",
3910
+ hint="format must be one of: json, yaml, github-comment.",
3911
+ expected="json | yaml | github-comment",
3912
+ )
3913
+ raise typer.Exit(code=1)
3914
+
3821
3915
  file_list = find_java_files(target)
3822
3916
  if not file_list:
3823
- data = SpringAuditResult(
3917
+ empty_result = SpringAuditResult(
3824
3918
  spring_detected=False,
3825
3919
  scope=scope,
3826
3920
  limitations=["No Java files found in repository — Spring audit requires Java source."],
3827
3921
  metadata={"java_files_found": 0},
3828
- ).finalize().to_dict()
3829
- output = _serialize_dict(data, format)
3922
+ ).finalize()
3923
+ if format == "github-comment":
3924
+ output = _render_spring_audit_github_comment(empty_result, min_severity)
3925
+ else:
3926
+ output = _serialize_dict(empty_result.to_dict(), format)
3830
3927
  if output_path is not None:
3831
3928
  output_path.write_text(output, encoding="utf-8")
3832
3929
  typer.echo("Spring audit written to " + str(output_path), err=True)
@@ -3885,7 +3982,10 @@ def spring_audit_cmd(
3885
3982
  except Exception:
3886
3983
  pass
3887
3984
 
3888
- output = _serialize_dict(data, format)
3985
+ if format == "github-comment":
3986
+ output = _render_spring_audit_github_comment(combined, min_severity)
3987
+ else:
3988
+ output = _serialize_dict(data, format)
3889
3989
 
3890
3990
  if output_path is not None:
3891
3991
  output_path.write_text(output, encoding="utf-8")
@@ -3899,6 +3999,9 @@ def spring_audit_cmd(
3899
3999
  if _copy_to_clipboard(output):
3900
4000
  typer.echo("✓ copied to clipboard", err=True)
3901
4001
 
4002
+ if ci and combined.findings:
4003
+ raise typer.Exit(code=1)
4004
+
3902
4005
 
3903
4006
  # ── Spring Boot Migration Check ───────────────────────────────────────────────
3904
4007
 
@@ -1221,6 +1221,7 @@ _MCP_HIDDEN_CANONICAL_TOOLS: frozenset[str] = frozenset({
1221
1221
  # Listed here so validate_registry() skips CLI param-drift checks on the alias.
1222
1222
  "spring_audit", # curated: repo_path + scope + min_severity only (strips output_path/format/copy)
1223
1223
  "impact_chain", # curated: repo_path + symbol + depth + query_type with choices
1224
+ "migrate_check", # curated: repo_path + min_severity only (strips output_path/format/copy/ci)
1224
1225
  # MCP self-management (an agent is not the MCP client admin)
1225
1226
  "mcp_init",
1226
1227
  "mcp_serve",
@@ -1349,7 +1350,57 @@ query_type: "impact" (default) | "events"
1349
1350
  docstring_override=_IMPACT_CHAIN_DOC,
1350
1351
  )
1351
1352
 
1352
- return [spring_audit, impact_chain]
1353
+ _MIGRATE_CHECK_DOC = """\
1354
+ Spring Boot 2→3 migration readiness: javax→jakarta namespace blockers. JAVA ONLY.
1355
+
1356
+ When to call: when asked about Spring Boot migration readiness, javax vs jakarta imports,
1357
+ or upgrading from Spring Boot 2.x to 3.x. Use BEFORE get_spring_audit when the goal
1358
+ is migration planning rather than ongoing Spring semantic audit.
1359
+ Do NOT call on non-Java repositories — returns readiness_score=100 with no findings.
1360
+
1361
+ Rules detected:
1362
+ MIG-001 critical — javax.persistence imports (JPA; will not compile after migration)
1363
+ MIG-002 high — javax.servlet imports (Servlet API changed)
1364
+ MIG-003 high — javax.validation imports (Bean Validation changed)
1365
+ MIG-004 high — javax.transaction imports (TX API changed)
1366
+ MIG-005 high — extends WebSecurityConfigurerAdapter (removed in Spring Security 6)
1367
+ MIG-006 medium — javax.annotation imports (CDI annotations)
1368
+ MIG-007 medium — javax.inject imports (DI annotations)
1369
+ MIG-008 medium — javax.ws.rs imports (JAX-RS API)
1370
+
1371
+ Returns: schema_version, readiness_score (0–100; 100=ready to migrate), blocking_count,
1372
+ estimated_effort_days, spring_boot_2_detected, summary (total_findings, affected_files,
1373
+ by_severity, by_rule), findings[], limitations, metadata.
1374
+ findings fields: id, rule_id, severity, title, source_file, first_line,
1375
+ imports_found, explanation, fix_hint.
1376
+
1377
+ repo_path: absolute path to the Java repository (default: current working directory).
1378
+ min_severity: "low" (default) | "medium" | "high" | "critical" — filter threshold.
1379
+ """
1380
+
1381
+ migrate_check = _alias_spec(
1382
+ "migrate_check",
1383
+ "Spring Boot 2→3 migration readiness: javax→jakarta blockers. JAVA ONLY.",
1384
+ ("migrate-check",),
1385
+ (
1386
+ ToolParamSpec("repo_path", "argument", str, required=False, default=".", is_path=True,
1387
+ help="Absolute path to the Java repository."),
1388
+ ToolParamSpec("min_severity", "option", str, required=False, default="low",
1389
+ option_names=("--min-severity",), choices=("low", "medium", "high", "critical"),
1390
+ help="low (default) | medium | high | critical"),
1391
+ ),
1392
+ lambda inputs: [
1393
+ "migrate-check",
1394
+ str(inputs.get("repo_path", ".")),
1395
+ "--min-severity", str(inputs.get("min_severity", "low")),
1396
+ ],
1397
+ supported_targets=("repo_path",),
1398
+ unsupported_targets=("file_path",),
1399
+ validator=validate_repo_path,
1400
+ docstring_override=_MIGRATE_CHECK_DOC,
1401
+ )
1402
+
1403
+ return [spring_audit, impact_chain, migrate_check]
1353
1404
 
1354
1405
 
1355
1406
  @lru_cache(maxsize=1)
@@ -649,6 +649,56 @@ def get_spring_audit(repo_path: str = ".", scope: str = "all") -> dict:
649
649
  )
650
650
 
651
651
 
652
+ @mcp.tool()
653
+ def get_migration_readiness(repo_path: str = ".", min_severity: str = "low") -> dict:
654
+ """Spring Boot 2→3 migration readiness: javax→jakarta namespace blockers. JAVA ONLY.
655
+
656
+ When to call: when asked about Spring Boot migration readiness, javax vs jakarta imports,
657
+ or upgrading from Spring Boot 2.x to 3.x. Call this BEFORE get_spring_audit when
658
+ the goal is migration planning — not ongoing audit.
659
+ Do NOT call on non-Java repositories — returns readiness_score=100 with no findings.
660
+
661
+ Maps to: sourcecode migrate-check <repo_path> --min-severity <min_severity>
662
+ Returns: MigrationReport with schema_version, readiness_score (0–100; 100=ready to migrate),
663
+ blocking_count, estimated_effort_days, spring_boot_2_detected,
664
+ summary (total_findings, affected_files, by_severity, by_rule),
665
+ findings[], limitations, metadata.
666
+ findings fields: id, rule_id, severity, title, source_file, first_line,
667
+ imports_found, explanation, fix_hint.
668
+ Rules:
669
+ MIG-001 critical — javax.persistence (JPA, will not compile after migration)
670
+ MIG-002 high — javax.servlet (Servlet API)
671
+ MIG-003 high — javax.validation (Bean Validation)
672
+ MIG-004 high — javax.transaction (TX API)
673
+ MIG-005 high — extends WebSecurityConfigurerAdapter (removed in Spring Security 6)
674
+ MIG-006 medium — javax.annotation (CDI annotations)
675
+ MIG-007 medium — javax.inject (DI annotations)
676
+ MIG-008 medium — javax.ws.rs (JAX-RS API)
677
+
678
+ repo_path: absolute path to the Java repository (default: current working directory).
679
+ min_severity: "low" (default) | "medium" | "high" | "critical" — filter threshold.
680
+ """
681
+ _raw = repo_path
682
+ try:
683
+ if not isinstance(repo_path, str):
684
+ return _err("repo_path must be a string", "INVALID_ARGUMENT")
685
+ if min_severity not in ("critical", "high", "medium", "low"):
686
+ return _err(
687
+ f"Invalid min_severity '{min_severity}' — must be one of: critical, high, medium, low",
688
+ "INVALID_ARGUMENT",
689
+ )
690
+ repo_path = _normalize_repo_path(repo_path)
691
+ _path_err = _check_repo_path(repo_path)
692
+ if _path_err is not None:
693
+ return _path_err
694
+ return _execute(["migrate-check", repo_path, "--min-severity", min_severity])
695
+ except Exception as exc:
696
+ return _err(
697
+ f"Internal error: {type(exc).__name__}: {exc} — repo_path recibido: {_raw}",
698
+ "INTERNAL_ERROR",
699
+ )
700
+
701
+
652
702
  @mcp.tool()
653
703
  def get_impact_chain(repo_path: str = ".", symbol: str = "", depth: int = 4) -> dict:
654
704
  """Spring impact-chain: systemic blast radius of a symbol with TX/SEC semantic enrichment. JAVA/SPRING ONLY.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes