invar-tools 1.16.0__py3-none-any.whl → 1.17.1__py3-none-any.whl

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.
@@ -84,6 +84,46 @@ class TypeScriptGuardResult:
84
84
  enhanced: EnhancedAnalysis | None = None
85
85
 
86
86
 
87
+ # DX-22: Fix-or-Explain complexity debt enforcement
88
+ # @shell_orchestration: Checks project-level complexity debt
89
+ def check_ts_complexity_debt(
90
+ violations: list[TypeScriptViolation], limit: int = 3
91
+ ) -> list[TypeScriptViolation]:
92
+ """Check project-level shell-complexity debt (DX-22 Fix-or-Explain).
93
+
94
+ When the project has too many unaddressed shell-complexity warnings,
95
+ escalate to ERROR to force resolution. TypeScript default is 3 (vs Python's 5)
96
+ since TS projects tend to be smaller.
97
+
98
+ Args:
99
+ violations: All violations from ESLint/tsc/vitest.
100
+ limit: Maximum unaddressed complexity warnings before ERROR (default 3).
101
+
102
+ Returns:
103
+ List with single ERROR violation if debt limit exceeded, empty list otherwise.
104
+ """
105
+ # Count unaddressed shell-complexity warnings
106
+ unaddressed = [
107
+ v
108
+ for v in violations
109
+ if v.rule == "@invar/shell-complexity" and v.severity == "warning"
110
+ ]
111
+
112
+ if len(unaddressed) >= limit:
113
+ return [
114
+ TypeScriptViolation(
115
+ file="<project>",
116
+ line=None,
117
+ column=None,
118
+ rule="@invar/shell-complexity-debt",
119
+ message=f"Project has {len(unaddressed)} unaddressed complexity warnings (limit: {limit})",
120
+ severity="error",
121
+ source="eslint",
122
+ )
123
+ ]
124
+ return []
125
+
126
+
87
127
  # @shell_orchestration: Transforms TypeScriptGuardResult to JSON for agent consumption
88
128
  def format_typescript_guard_v2(result: TypeScriptGuardResult) -> dict:
89
129
  """Format TypeScript guard result as v2.0 JSON.
@@ -403,8 +443,32 @@ def run_ts_analyzer(project_path: Path) -> Result[dict, str]:
403
443
  # ts-analyzer exits non-zero when critical blind spots found, but still outputs valid JSON
404
444
  # Try to parse JSON output regardless of exit code
405
445
  if result.stdout.strip():
406
- with contextlib.suppress(json.JSONDecodeError):
407
- return Success(json.loads(result.stdout))
446
+ try:
447
+ data = json.loads(result.stdout)
448
+ return Success(data)
449
+ except json.JSONDecodeError as e:
450
+ # JSON too large or malformed - try to extract summary from text output
451
+ # Fall back to running without --json flag for human-readable summary
452
+ try:
453
+ summary_result = subprocess.run(
454
+ [*cmd, str(project_path)],
455
+ capture_output=True,
456
+ text=True,
457
+ timeout=60,
458
+ cwd=project_path,
459
+ )
460
+ # Extract key metrics from text output
461
+ output = summary_result.stdout
462
+ coverage_match = re.search(r'Contract coverage: (\d+)%', output)
463
+ coverage = int(coverage_match.group(1)) if coverage_match else None
464
+
465
+ return Success({
466
+ "coverage": coverage,
467
+ "summary_mode": True,
468
+ "note": "Full JSON output too large, using summary metrics"
469
+ })
470
+ except Exception:
471
+ return Failure(f"JSON parse error: {str(e)[:100]}")
408
472
 
409
473
  # Only report failure if no valid JSON output
410
474
  if "not found" in result.stderr.lower() or "ENOENT" in result.stderr:
@@ -750,7 +814,8 @@ def run_vitest(project_path: Path) -> Result[list[TypeScriptViolation], str]:
750
814
  deps = {**pkg.get("dependencies", {}), **pkg.get("devDependencies", {})}
751
815
  if "vitest" not in deps:
752
816
  return Success([]) # No vitest configured, skip
753
- except json.JSONDecodeError:
817
+ except (json.JSONDecodeError, OSError):
818
+ # Handle both JSON parse errors and IO errors (file deleted, permission denied, etc.)
754
819
  pass
755
820
 
756
821
  # LX-15 Phase 1: Generate doctests before running vitest
@@ -860,8 +925,19 @@ def run_typescript_guard(
860
925
  match eslint_result:
861
926
  case Success(violations):
862
927
  all_violations.extend(violations)
863
- case Failure(_):
864
- pass # ESLint errors are non-fatal
928
+ case Failure(err):
929
+ # Report ESLint failure as a violation instead of silently ignoring
930
+ all_violations.append(
931
+ TypeScriptViolation(
932
+ file="<eslint>",
933
+ line=0,
934
+ column=0,
935
+ rule="eslint-error",
936
+ message=f"ESLint failed to run: {err}",
937
+ severity="error",
938
+ source="eslint",
939
+ )
940
+ )
865
941
 
866
942
  # Run vitest
867
943
  if result.vitest_available and not skip_tests:
@@ -911,6 +987,10 @@ def run_typescript_guard(
911
987
 
912
988
  result.enhanced = enhanced
913
989
 
990
+ # DX-22: Check for complexity debt (project-level Fix-or-Explain enforcement)
991
+ complexity_debt_violations = check_ts_complexity_debt(all_violations, limit=3)
992
+ all_violations.extend(complexity_debt_violations)
993
+
914
994
  # Aggregate results
915
995
  result.violations = all_violations
916
996
  result.error_count = sum(1 for v in all_violations if v.severity == "error")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: invar-tools
3
- Version: 1.16.0
3
+ Version: 1.17.1
4
4
  Summary: AI-native software engineering tools with design-by-contract verification
5
5
  Project-URL: Homepage, https://github.com/tefx/invar
6
6
  Project-URL: Documentation, https://github.com/tefx/invar#readme
@@ -8,7 +8,7 @@ invar/core/entry_points.py,sha256=1p6GRGTp9kA9spNkGKidFLlzLPheh6JO2XFb68Cr0sE,12
8
8
  invar/core/extraction.py,sha256=mScqEMEEQdsd-Z0jx9g3scK6Z1vI9l-ESjggXPIWHZ4,6112
9
9
  invar/core/feedback.py,sha256=JhQf32y_Qutza8D2b5qX2U4fM--vtR3sBdV22KrVNY0,3246
10
10
  invar/core/format_specs.py,sha256=P299aRHFMXyow8STwsvaT6Bg2ALPs2wSy7SByiRZZ-A,5610
11
- invar/core/format_strategies.py,sha256=LifL97JbsF8WEkVNmQpq2htyFUC3pW21myAjtRGpSxU,5774
11
+ invar/core/format_strategies.py,sha256=laWixu7AV2GdKNK886Eu-3NLHRdQT-hH_HOQdgIAjKI,5848
12
12
  invar/core/formatter.py,sha256=rCGZhMpl4dPLrztgKDkNtAvnv2vKfomyIHl_6fThuno,11293
13
13
  invar/core/hypothesis_strategies.py,sha256=_MfjG7KxkmJvuPsczr_1JayR_YmiDzU2jJ8fQPoKGgs,16517
14
14
  invar/core/inspect.py,sha256=l1knohwpLRHSNySPUjyeBHJusnU0vYiQGj4dMVgQZIo,4381
@@ -50,14 +50,25 @@ invar/core/patterns/registry.py,sha256=2rz0wWDRarMkuHN-qM_ZrT3qeGFDSKMABvRvPNZxQ
50
50
  invar/core/patterns/types.py,sha256=ULAlWuAdmO6CFcEDjTrWBfzNTBsnomAl2d25tR11ihU,5506
51
51
  invar/mcp/__init__.py,sha256=n3S7QwMjSMqOMT8cI2jf9E0yZPjKmBOJyIYhq4WZ8TQ,226
52
52
  invar/mcp/__main__.py,sha256=ZcIT2U6xUyGOWucl4jq422BDE3lRLjqyxb9pFylRBdk,219
53
- invar/mcp/handlers.py,sha256=b0LRWKMpu6lnjPV7SozH0cxKYJufVWy3eJhiAu3of-M,15947
53
+ invar/mcp/handlers.py,sha256=Kls1aXnYmGcMvib_Mesfz5FjBaL7lmrhKaw_P2JDnyw,16551
54
54
  invar/mcp/server.py,sha256=WmVNs2_AcOMbmp3tEgWR57hjqqJkMx3nV3z9fcNuSAA,20109
55
55
  invar/node_tools/.gitignore,sha256=Tu_FtBhQTKPl9LHokxUTCTcxPadynDy6VPo0Z1WCBAQ,388
56
56
  invar/node_tools/MANIFEST,sha256=2Z2at-27MK8K7DSjOjjtR4faTbt6eCiKQuEfvP_lwH8,145
57
57
  invar/node_tools/__init__.py,sha256=HzILh3jtP28Lm2jZwss1SY65ECxbtw2J2uFpXQA6Y94,1740
58
58
  invar/node_tools/ts-query.js,sha256=fEc_f0JT_Mb18dEoA4_vJoazvd7Lqv_rsed4eHSAbCg,13303
59
- invar/node_tools/eslint-plugin/cli.js,sha256=TyBGCIZ0LiGIEjESRCh1VkY5ooLmrRbFY9dd5Vfzw9c,4647
60
- invar/node_tools/fc-runner/cli.js,sha256=72_gIhvnx2peKITdzdnFWI5fzGaNTS3BcEqyS628cI0,243277
59
+ invar/node_tools/eslint-plugin/cli.js,sha256=8LxwmRzIvHjkOuhy7Vt8_pOXg5Vfj6XyoRydSOBtc4k,6620
60
+ invar/node_tools/eslint-plugin/cli.js.map,sha256=oaqf-w1ySV7gGLcEVTaoY6G7gZ_R66eoZGYro6zvbX8,4266
61
+ invar/node_tools/eslint-plugin/index.js,sha256=atrI37dn1yDznQrgKY-1xIhLnCdvJQTU53123ZI_9J4,5132
62
+ invar/node_tools/eslint-plugin/index.js.map,sha256=MlFuNso9sZ4v9ggGJLyMq4Pt_JdEzP1OyouyCCki1wA,2344
63
+ invar/node_tools/fc-runner/bundle.js,sha256=D1wDqXYDOwWU4eqXeZdLIFvSsJ36q56Ay_ipLdklQPw,243285
64
+ invar/node_tools/fc-runner/cli.d.ts,sha256=UM1WM4OKVvABXIsTHt6VHdO_oQMlgltUFV6CIqeh1B0,294
65
+ invar/node_tools/fc-runner/cli.d.ts.map,sha256=-R1m4uJf2vmDZEpU7pEaib6TVjd0YuQnTQEGwkN6I9Q,117
66
+ invar/node_tools/fc-runner/cli.js,sha256=8T_YWJMmWEQmbCFsG8r4R03mi5qGpkfhitsh_5o455c,5007
67
+ invar/node_tools/fc-runner/cli.js.map,sha256=G4ecWIoU7P1ME12tM09_4N_Y6tppFNlrL3IWNPwKR2g,4195
68
+ invar/node_tools/fc-runner/index.d.ts,sha256=ejHHCxatrAbDSHWuHsedGHLnpLNa6ek7rowZLdf_NiY,12615
69
+ invar/node_tools/fc-runner/index.d.ts.map,sha256=MK73QKaDi8IhZ7Diphvs2sYNYbmpNIobXHbUNQBaKNg,1699
70
+ invar/node_tools/fc-runner/index.js,sha256=A0ard14fRX6ZnKjtONPGyE1EUMuRN9K-InCPwGIRuPU,8782
71
+ invar/node_tools/fc-runner/index.js.map,sha256=2ASF8aJUvuYqBgnfL0rxw4xRSK6ur23G0HGn5w0IQZI,6754
61
72
  invar/node_tools/quick-check/cli.js,sha256=dwV3hdJleFQga2cKUn3PPfQDvvujhzKdjQcIvWsKgM0,66196
62
73
  invar/node_tools/ts-analyzer/cli.js,sha256=SvZ6HyjmobpP8NAZqXFiy8BwH_t5Hb17Ytar_18udaQ,4092887
63
74
  invar/shell/__init__.py,sha256=FFw1mNbh_97PeKPcHIqQpQ7mw-JoIvyLM1yOdxLw5uk,204
@@ -102,7 +113,7 @@ invar/shell/prove/__init__.py,sha256=ZqlbmyMFJf6yAle8634jFuPRv8wNvHps8loMlOJyf8A
102
113
  invar/shell/prove/accept.py,sha256=cnY_6jzU1EBnpLF8-zWUWcXiSXtCwxPsXEYXsSVPG38,3717
103
114
  invar/shell/prove/cache.py,sha256=jbNdrvfLjvK7S0iqugErqeabb4YIbQuwIlcSRyCKbcg,4105
104
115
  invar/shell/prove/crosshair.py,sha256=XhJDsQWIriX9SuqeflUYvJgp9gJTDH7I7Uka6zjNzZ0,16734
105
- invar/shell/prove/guard_ts.py,sha256=i0F_56_aIgtqzJF2pfRAYJ2Tyjsuv-xhT8N_ZsBfis8,32567
116
+ invar/shell/prove/guard_ts.py,sha256=4wY2QyyOXJ6eRjHWd6M4l866i3_o6AmfffFQVq7Q5xU,35886
106
117
  invar/shell/prove/hypothesis.py,sha256=QUclOOUg_VB6wbmHw8O2EPiL5qBOeBRqQeM04AVuLw0,9880
107
118
  invar/templates/CLAUDE.md.template,sha256=eaGU3SyRO_NEifw5b26k3srgQH4jyeujjCJ-HbM36_w,4913
108
119
  invar/templates/__init__.py,sha256=cb3ht8KPK5oBn5oG6HsTznujmo9WriJ_P--fVxJwycc,45
@@ -183,10 +194,10 @@ invar/templates/skills/invar-reflect/template.md,sha256=Rr5hvbllvmd8jSLf_0ZjyKt6
183
194
  invar/templates/skills/investigate/SKILL.md.jinja,sha256=cp6TBEixBYh1rLeeHOR1yqEnFqv1NZYePORMnavLkQI,3231
184
195
  invar/templates/skills/propose/SKILL.md.jinja,sha256=6BuKiCqO1AEu3VtzMHy1QWGqr_xqG9eJlhbsKT4jev4,3463
185
196
  invar/templates/skills/review/SKILL.md.jinja,sha256=ET5mbdSe_eKgJbi2LbgFC-z1aviKcHOBw7J5Q28fr4U,14105
186
- invar_tools-1.16.0.dist-info/METADATA,sha256=JUYnszfz8YwiI3iRSXAlSnpVnCtBOtHGT5eeUb7w68w,28595
187
- invar_tools-1.16.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
188
- invar_tools-1.16.0.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
189
- invar_tools-1.16.0.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
190
- invar_tools-1.16.0.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
191
- invar_tools-1.16.0.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
192
- invar_tools-1.16.0.dist-info/RECORD,,
197
+ invar_tools-1.17.1.dist-info/METADATA,sha256=Wf6in5vtQoakdWj7GzkV1EIsCV46h_QNqZPADbwtqGY,28595
198
+ invar_tools-1.17.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
199
+ invar_tools-1.17.1.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
200
+ invar_tools-1.17.1.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
201
+ invar_tools-1.17.1.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
202
+ invar_tools-1.17.1.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
203
+ invar_tools-1.17.1.dist-info/RECORD,,