leanback 0.1.0__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: leanback
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: MCP server for Lean 4 theorem proving — check, prove, goals, eval, search
5
5
  Author: Stefan Szeider
6
6
  License: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "leanback"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  description = "MCP server for Lean 4 theorem proving — check, prove, goals, eval, search"
9
9
  readme = "README.md"
10
10
  license = { text = "Apache-2.0" }
@@ -1,3 +1,3 @@
1
1
  """LeanBack - Lean 4 development tools for Claude Code."""
2
2
 
3
- __version__ = "0.3.0"
3
+ __version__ = "0.1.2"
@@ -295,8 +295,8 @@ def check_project(
295
295
  lean_files = list(project_path.glob("**/*.lean"))
296
296
 
297
297
  for file_path in lean_files:
298
- # Skip files in .lake directory
299
- if ".lake" in file_path.parts:
298
+ # Skip files in .lake directory and lakefile.lean (uses Lake DSL, not standard Lean)
299
+ if ".lake" in file_path.parts or file_path.name == "lakefile.lean":
300
300
  continue
301
301
 
302
302
  console.print(f"Checking {file_path.relative_to(project_path)}...")
@@ -3,6 +3,7 @@
3
3
 
4
4
  import argparse
5
5
  import functools
6
+ import importlib.metadata
6
7
  import inspect
7
8
  import json
8
9
  import logging
@@ -169,11 +170,26 @@ def _clean_lean_message(message: str) -> str:
169
170
  return message
170
171
 
171
172
 
172
- def _serialize_errors(errors: list, sanitize_paths: bool = False) -> list[dict]:
173
- """Serialize LeanError objects to dicts for JSON output."""
173
+ def _serialize_errors(
174
+ errors: list, sanitize_paths: bool = False, source_file: str | None = None
175
+ ) -> list[dict]:
176
+ """Serialize LeanError objects to dicts for JSON output.
177
+
178
+ If source_file is provided, temp file paths are replaced with it
179
+ instead of the generic '<inline>' label.
180
+ """
181
+
182
+ def _resolve_path(file_name: str) -> str:
183
+ if not sanitize_paths:
184
+ return file_name
185
+ sanitized = _sanitize_file_path(file_name)
186
+ if sanitized == "<inline>" and source_file:
187
+ return source_file
188
+ return sanitized
189
+
174
190
  return [
175
191
  {
176
- "file": _sanitize_file_path(e.file_name) if sanitize_paths else e.file_name,
192
+ "file": _resolve_path(e.file_name),
177
193
  "line": e.line,
178
194
  "column": e.column,
179
195
  "end_line": e.end_line,
@@ -242,7 +258,7 @@ def project_info(project: str) -> str:
242
258
  Returns JSON with project status. Possible scenarios:
243
259
 
244
260
  1. Valid project with Mathlib:
245
- {"valid": true, "lean_version": "...", "has_mathlib": true, "built": true}
261
+ {"valid": true, "leanback_version": "0.1.0", "lean_version": "...", "has_mathlib": true, "built": true}
246
262
 
247
263
  2. Path does not exist (includes setup commands):
248
264
  {"valid": false, "reason": "path_not_found", "setup_commands": [...]}
@@ -328,7 +344,11 @@ def project_info(project: str) -> str:
328
344
  )
329
345
 
330
346
  # Valid Lean project — gather diagnostics
331
- result = {"valid": True}
347
+ try:
348
+ leanback_ver = importlib.metadata.version("leanback")
349
+ except importlib.metadata.PackageNotFoundError:
350
+ leanback_ver = "dev"
351
+ result = {"valid": True, "leanback_version": leanback_ver}
332
352
 
333
353
  # Lean version
334
354
  toolchain_file = p / "lean-toolchain"
@@ -408,7 +428,7 @@ def check(
408
428
  - file: Path to a .lean file within the project (e.g., "Basic.lean", "src/Logic.lean")
409
429
  - check_all: Check each file individually for detailed error reporting (slower but more thorough)
410
430
  - expr: A Lean expression or command to check (e.g., "2 + 2 = 4", "Nat.add", "#eval 1 + 1"). Bare expressions are auto-wrapped in #check.
411
- - imports: List of modules to import when checking expressions (e.g., ["Mathlib.Tactic"])
431
+ - imports: List of modules to import when checking expressions (e.g., ["Mathlib.Tactic"]). First Mathlib import takes ~20-30s.
412
432
 
413
433
  Returns JSON with 'success' boolean. The 'messages' array contains objects with:
414
434
  - file: Path to the file (or "<inline>" for expressions)
@@ -560,6 +580,12 @@ def check(
560
580
  "files_checked": 1,
561
581
  },
562
582
  }
583
+ if file_path.name == "lakefile.lean" and not success:
584
+ result["note"] = (
585
+ "lakefile.lean uses Lake DSL which may produce errors "
586
+ "when checked outside the build system. "
587
+ "These errors are typically not actionable."
588
+ )
563
589
  return _json(result)
564
590
 
565
591
  # Case 3: Check entire project
@@ -615,7 +641,7 @@ def prove(
615
641
  - tactics: List of proof tactics to apply in order (e.g., ["intro n", "rfl"])
616
642
  - file: Path to a .lean file containing complete proofs to verify
617
643
  - imports: Additional modules to import (e.g., ["Mathlib.Data.Nat.Basic"])
618
- - mathlib: Import Mathlib.Tactic for all standard tactics (simp, ring, omega, linarith, norm_num, decide, aesop, etc.)
644
+ - mathlib: Import Mathlib.Tactic for all standard tactics (simp, ring, omega, linarith, norm_num, decide, aesop, etc.). First call takes ~8-11s for import.
619
645
 
620
646
  Use either (theorem + tactics) OR (file), not both. When using theorem + tactics,
621
647
  the tool constructs and verifies the proof. When using file, it verifies existing proofs.
@@ -793,7 +819,7 @@ def goals(
793
819
  - theorem: Theorem statement to prove (e.g., "2 + 2 = 4", "∀ n : Nat, n + 0 = n")
794
820
  - tactics: List of tactics applied so far (e.g., ["intro n"]). Omit or pass [] to see the initial goal.
795
821
  - imports: Additional modules to import (e.g., ["Mathlib.Data.Nat.Basic"])
796
- - mathlib: Import Mathlib.Tactic for standard tactics (simp, ring, omega, linarith, norm_num, decide, aesop, etc.)
822
+ - mathlib: Import Mathlib.Tactic for standard tactics (simp, ring, omega, linarith, norm_num, decide, aesop, etc.). First call takes ~8-11s for import.
797
823
 
798
824
  Returns JSON with:
799
825
  - success: Whether the tool ran without internal errors
@@ -879,7 +905,7 @@ def eval(
879
905
  - code: Lean code to execute (e.g., "#eval 2 + 2", "#check Nat.add", "def f := 5")
880
906
  - file: Path to a .lean file to execute instead of inline code
881
907
  - imports: Additional modules to import (e.g., ["Mathlib.Data.Finset.Basic"])
882
- - mathlib: Import Mathlib.Tactic for all standard tactics (simp, ring, omega, linarith, norm_num, decide, aesop, etc.)
908
+ - mathlib: Import Mathlib.Tactic for all standard tactics (simp, ring, omega, linarith, norm_num, decide, aesop, etc.). First call takes ~8-11s for import.
883
909
 
884
910
  Use either 'code' OR 'file', not both. The tool can handle multi-line code.
885
911
 
@@ -979,7 +1005,9 @@ def eval(
979
1005
  "type": "code_execution",
980
1006
  "code": code_to_execute,
981
1007
  "imports": resolved_imports,
982
- "messages": _serialize_errors(errors, sanitize_paths=True),
1008
+ "messages": _serialize_errors(
1009
+ errors, sanitize_paths=True, source_file=file
1010
+ ),
983
1011
  }
984
1012
  )
985
1013
 
@@ -1084,6 +1112,12 @@ def search(
1084
1112
  )
1085
1113
 
1086
1114
  results = batch_search_declarations(patterns, project_path, **search_params)
1115
+ if isinstance(results, dict):
1116
+ results["note"] = (
1117
+ "Search covers Mathlib declarations only, "
1118
+ "not core Lean (e.g., Nat.add_comm, List.map). "
1119
+ "Use eval with #check to inspect core declarations."
1120
+ )
1087
1121
  return _json(results)
1088
1122
  else:
1089
1123
  try:
@@ -1117,6 +1151,11 @@ def search(
1117
1151
  "results": serializable_results,
1118
1152
  "metadata": metadata,
1119
1153
  }
1154
+ result["note"] = (
1155
+ "Search covers Mathlib declarations only, "
1156
+ "not core Lean (e.g., Nat.add_comm, List.map). "
1157
+ "Use eval with #check to inspect core declarations."
1158
+ )
1120
1159
  if len(serializable_results) == 0:
1121
1160
  if filter_namespace and total_found > 0:
1122
1161
  result["note"] = (
@@ -1128,7 +1167,7 @@ def search(
1128
1167
  result["note"] = (
1129
1168
  "No matches found. This search covers Mathlib declarations only, "
1130
1169
  "not core Lean (e.g., Nat.add_comm, List.map). "
1131
- "Try a broader pattern or check the declaration name."
1170
+ "Try a broader pattern, or use eval with #check to inspect core declarations."
1132
1171
  )
1133
1172
  return _json(result)
1134
1173
  except SearchError as e:
File without changes
File without changes
File without changes
File without changes
File without changes