invar-tools 1.17.6__py3-none-any.whl → 1.17.8__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.
@@ -15,12 +15,6 @@ from rich.console import Console
15
15
  from rich.table import Table
16
16
 
17
17
 
18
- def _detect_agent_mode() -> bool:
19
- """Detect agent context: INVAR_MODE=agent OR non-TTY (pipe/redirect)."""
20
- import sys
21
- return os.getenv("INVAR_MODE") == "agent" or not sys.stdout.isatty()
22
-
23
-
24
18
  from invar import __version__
25
19
  from invar.core.models import GuardReport, RuleConfig
26
20
  from invar.core.rules import check_all_rules
@@ -95,12 +89,14 @@ def _scan_and_check(
95
89
  for rule, reason, line in extract_escape_hatches(file_info.source):
96
90
  all_escapes.append((file_info.path, rule, reason))
97
91
  # DX-66: Add to escape hatch summary
98
- report.escape_hatches.add(EscapeHatchDetail(
99
- file=file_info.path,
100
- line=line,
101
- rule=rule,
102
- reason=reason,
103
- ))
92
+ report.escape_hatches.add(
93
+ EscapeHatchDetail(
94
+ file=file_info.path,
95
+ line=line,
96
+ rule=rule,
97
+ reason=reason,
98
+ )
99
+ )
104
100
 
105
101
  # DX-22: Check project-level complexity debt (Fix-or-Explain enforcement)
106
102
  for debt_violation in check_complexity_debt(
@@ -133,7 +129,7 @@ def guard(
133
129
  False, "--static", help="Static analysis only, skip all runtime tests"
134
130
  ),
135
131
  human: bool = typer.Option(
136
- False, "--human", help="Force human-readable output (for testing/debugging)"
132
+ False, "--human", help="Force Rich human-readable output (opt-in, default is JSON)"
137
133
  ),
138
134
  # DX-26: Deprecated flags kept for backward compatibility
139
135
  no_strict_pure: bool = typer.Option(
@@ -192,23 +188,12 @@ def guard(
192
188
  ts_result = run_typescript_guard(path if path.is_dir() else find_project_root(path))
193
189
  match ts_result:
194
190
  case Success(result):
195
- if json_output or agent:
196
- import json as json_mod
197
-
198
- from invar.shell.prove.guard_ts import format_typescript_guard_v2
199
-
200
- output = format_typescript_guard_v2(result)
201
- console.print(json_mod.dumps(output, indent=2))
202
- else:
203
- console.print(f"[bold]TypeScript Guard[/bold] ({project_language})")
204
- if result.status == "passed":
205
- console.print("[green]✓ PASSED[/green]")
206
- elif result.status == "skipped":
207
- console.print("[yellow]⚠ SKIPPED[/yellow] (no TypeScript tools available)")
208
- else:
209
- console.print(f"[red]✗ FAILED[/red] ({result.error_count} errors)")
210
- for v in result.violations[:10]: # Show first 10
211
- console.print(f" {v.file}:{v.line}: [{v.severity}] {v.message}")
191
+ import json as json_mod
192
+
193
+ from invar.shell.prove.guard_ts import format_typescript_guard_v2
194
+
195
+ output = format_typescript_guard_v2(result)
196
+ console.print(json_mod.dumps(output, indent=2))
212
197
  raise typer.Exit(0 if result.status == "passed" else 1)
213
198
  case Failure(err):
214
199
  console.print(f"[red]Error:[/red] {err}")
@@ -295,6 +280,7 @@ def guard(
295
280
  run_pattern_detection,
296
281
  suggestions_to_violations,
297
282
  )
283
+
298
284
  # Run pattern detection on checked files
299
285
  files_to_check = list(only_files) if only_files else None
300
286
  pattern_result = run_pattern_detection(path, files_to_check)
@@ -331,6 +317,7 @@ def guard(
331
317
  # DX-37: Check coverage availability if requested
332
318
  if coverage:
333
319
  from invar.shell.coverage import check_coverage_available
320
+
334
321
  cov_check = check_coverage_available()
335
322
  if isinstance(cov_check, Failure):
336
323
  console.print(f"[yellow]Warning:[/yellow] {cov_check.failure()}")
@@ -342,14 +329,19 @@ def guard(
342
329
 
343
330
  # Phase 1: Doctests (DX-37: with optional coverage)
344
331
  doctest_passed, doctest_output, doctest_coverage = run_doctests_phase(
345
- checked_files, explain, timeout=config.timeout_doctest,
332
+ checked_files,
333
+ explain,
334
+ timeout=config.timeout_doctest,
346
335
  collect_coverage=coverage,
347
336
  )
348
337
 
349
338
  # Phase 2: CrossHair symbolic verification
350
339
  # Note: CrossHair uses subprocess + symbolic execution, coverage not applicable
351
340
  crosshair_passed, crosshair_output = run_crosshair_phase(
352
- path, checked_files, doctest_passed, static_exit_code,
341
+ path,
342
+ checked_files,
343
+ doctest_passed,
344
+ static_exit_code,
353
345
  changed_mode=changed,
354
346
  timeout=config.timeout_crosshair,
355
347
  per_condition_timeout=config.timeout_crosshair_per_condition,
@@ -357,7 +349,9 @@ def guard(
357
349
 
358
350
  # Phase 3: Hypothesis property tests (DX-37: with optional coverage)
359
351
  property_passed, property_output, property_coverage = run_property_tests_phase(
360
- checked_files, doctest_passed, static_exit_code,
352
+ checked_files,
353
+ doctest_passed,
354
+ static_exit_code,
361
355
  collect_coverage=coverage,
362
356
  )
363
357
  elif verification_level == VerificationLevel.STATIC:
@@ -382,20 +376,31 @@ def guard(
382
376
  if property_coverage and property_coverage.get("collected"):
383
377
  coverage_output["phases_tracked"].append("hypothesis")
384
378
  if "overall_branch_coverage" in property_coverage:
385
- coverage_output["overall_branch_coverage"] = property_coverage["overall_branch_coverage"]
379
+ coverage_output["overall_branch_coverage"] = property_coverage[
380
+ "overall_branch_coverage"
381
+ ]
386
382
 
387
383
  # DX-26: Unified output (agent JSON or human Rich)
388
384
  if use_agent_output:
389
385
  output_agent(
390
- report, strict, doctest_passed, doctest_output, crosshair_output, level_name,
386
+ report,
387
+ strict,
388
+ doctest_passed,
389
+ doctest_output,
390
+ crosshair_output,
391
+ level_name,
391
392
  property_output=property_output,
392
393
  coverage_data=coverage_output, # DX-37
393
394
  )
394
395
  else:
395
396
  output_rich(report, config.strict_pure, changed, pedantic, explain, static)
396
397
  output_verification_status(
397
- verification_level, static_exit_code, doctest_passed,
398
- doctest_output, crosshair_output, explain,
398
+ verification_level,
399
+ static_exit_code,
400
+ doctest_passed,
401
+ doctest_output,
402
+ crosshair_output,
403
+ explain,
399
404
  property_output=property_output,
400
405
  strict=strict,
401
406
  )
@@ -405,7 +410,9 @@ def guard(
405
410
  overall = coverage_output.get("overall_branch_coverage", 0.0)
406
411
  console.print(f"\n[bold]Coverage Analysis[/bold] ({' + '.join(phases)})")
407
412
  console.print(f" Overall branch coverage: {overall}%")
408
- console.print(" [dim]Note: CrossHair uses symbolic execution; coverage not applicable.[/dim]")
413
+ console.print(
414
+ " [dim]Note: CrossHair uses symbolic execution; coverage not applicable.[/dim]"
415
+ )
409
416
 
410
417
  # Exit with combined status
411
418
  all_passed = doctest_passed and crosshair_passed and property_passed
@@ -415,24 +422,23 @@ def guard(
415
422
 
416
423
  # @shell_orchestration: Output mode decision helper for CLI
417
424
  def _determine_output_mode(human: bool, agent: bool = False, json_output: bool = False) -> bool:
418
- """Determine if agent JSON output should be used (DX-26).
425
+ """Determine if agent JSON output should be used (Agent First).
419
426
 
420
- DX-26: TTY auto-detection with --human override.
421
- - --human flag human output (for testing/debugging)
422
- - TTY (terminal) → human output
423
- - Non-TTY (pipe/redirect) → agent JSON output
424
- - Deprecated --agent/--json flagsstill work for backward compat
427
+ Agent First principle: Machine-readable JSON is the default output format.
428
+ Human-readable Rich output is opt-in via --human flag.
429
+
430
+ Priority:
431
+ - --human flaghuman output (Rich, colored)
432
+ - Default → JSON output (machine-readable, Agent Native)
433
+ - --agent/--json flags → no-op (already default, kept for backward compat)
425
434
  """
426
- # --human flag always forces human output
435
+ # --human flag forces human output (priority highest)
427
436
  if human:
428
437
  return False # use_agent = False
429
438
 
430
- # Deprecated flags (backward compat)
431
- if json_output or agent:
432
- return True # use_agent = True
433
-
434
- # TTY auto-detection
435
- return _detect_agent_mode() # Returns True if non-TTY
439
+ # Default to JSON output (Agent First)
440
+ # --agent/--json are now no-ops but kept for backward compatibility
441
+ return True
436
442
 
437
443
 
438
444
  def _show_verification_level(verification_level) -> None:
@@ -464,8 +470,9 @@ def map_command(
464
470
  """Generate symbol map with reference counts."""
465
471
  from invar.shell.commands.perception import run_map
466
472
 
467
- # Phase 9 P11: Auto-detect agent mode
468
- use_json = json_output or _detect_agent_mode()
473
+ # Agent First: Default to JSON output
474
+ # --json is now a no-op (kept for backward compat)
475
+ use_json = True
469
476
  result = run_map(path, top, use_json)
470
477
  if isinstance(result, Failure):
471
478
  console.print(f"[red]Error:[/red] {result.failure()}")
@@ -480,8 +487,9 @@ def sig_command(
480
487
  """Extract signatures from a file or symbol."""
481
488
  from invar.shell.commands.perception import run_sig
482
489
 
483
- # Phase 9 P11: Auto-detect agent mode
484
- use_json = json_output or _detect_agent_mode()
490
+ # Agent First: Default to JSON output
491
+ # --json is now a no-op (kept for backward compat)
492
+ use_json = True
485
493
  result = run_sig(target, use_json)
486
494
  if isinstance(result, Failure):
487
495
  console.print(f"[red]Error:[/red] {result.failure()}")
@@ -504,8 +512,9 @@ def refs_command(
504
512
  """
505
513
  from invar.shell.commands.perception import run_refs
506
514
 
507
- # Auto-detect agent mode
508
- use_json = json_output or _detect_agent_mode()
515
+ # Agent First: Default to JSON output
516
+ # --json is now a no-op (kept for backward compat)
517
+ use_json = True
509
518
  result = run_refs(target, use_json)
510
519
  if isinstance(result, Failure):
511
520
  console.print(f"[red]Error:[/red] {result.failure()}")
@@ -529,8 +538,9 @@ def rules(
529
538
 
530
539
  from invar.core.rule_meta import RULE_META, RuleCategory, get_rules_by_category
531
540
 
532
- # Phase 9 P11: Auto-detect agent mode
533
- use_json = json_output or _detect_agent_mode()
541
+ # Agent First: Default to JSON output
542
+ # --json is now a no-op (kept for backward compat)
543
+ use_json = True
534
544
 
535
545
  # Filter by category if specified
536
546
  if category:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: invar-tools
3
- Version: 1.17.6
3
+ Version: 1.17.8
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
@@ -50,7 +50,7 @@ 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=Kls1aXnYmGcMvib_Mesfz5FjBaL7lmrhKaw_P2JDnyw,16551
53
+ invar/mcp/handlers.py,sha256=gutZuiukdfANWJliRtqX0xV7__MDwMs8C1U3H-R_hDs,16736
54
54
  invar/mcp/server.py,sha256=zSpY9bCFuq4mWe7XfolTnwHffhdmoyN40aFL4L7dFrE,20407
55
55
  invar/node_tools/.gitignore,sha256=M2kz8Iw7Kzmi44mKo1r7_HOZMh79a7dFDdRrqXyaEhI,530
56
56
  invar/node_tools/MANIFEST,sha256=2Z2at-27MK8K7DSjOjjtR4faTbt6eCiKQuEfvP_lwH8,145
@@ -2614,8 +2614,8 @@ invar/node_tools/eslint-plugin/rules/no-runtime-imports.js,sha256=GxlLKHzid3eSbO
2614
2614
  invar/node_tools/eslint-plugin/rules/no-runtime-imports.js.map,sha256=9bpNyMo9l3mIChn1sTWh40_dVYRaopUnUrnncvWEpmE,1348
2615
2615
  invar/node_tools/eslint-plugin/rules/require-complete-validation.js,sha256=ZGeAElzcIHsnNdMNb9wHShb8irCTkUhOBg-KIhV2Mes,3943
2616
2616
  invar/node_tools/eslint-plugin/rules/require-complete-validation.js.map,sha256=UhEr4fql0TObHt3ya8DydqbFlig5CSDFKIIJZSf74rA,2497
2617
- invar/node_tools/eslint-plugin/rules/require-jsdoc-example.js,sha256=Ad_TUhE_ly7H_hXR-9z4-8Pljm4gzO3-ikrKlyrR8Qw,3251
2618
- invar/node_tools/eslint-plugin/rules/require-jsdoc-example.js.map,sha256=uKqyODyMkvGigg15kee440mhn34BXZny2PtGzJL4vww,2216
2617
+ invar/node_tools/eslint-plugin/rules/require-jsdoc-example.js,sha256=Uql3FKdnTHFBMh_OkwGuOdMBzf4k94QHOaWo9frAcSM,4488
2618
+ invar/node_tools/eslint-plugin/rules/require-jsdoc-example.js.map,sha256=00cKhvu890f-8UXPZcEAaX44IjCxxw12E4l_gsi93JM,2960
2619
2619
  invar/node_tools/eslint-plugin/rules/require-schema-validation.js,sha256=gdJaRr9-j8ZmUr8-u_MnafeQ4I92OoIq3RzUXeqrpBg,12372
2620
2620
  invar/node_tools/eslint-plugin/rules/require-schema-validation.js.map,sha256=akTSZQq-OC6ZvwMklIBRaxsesJ9w6GHaPhRTJ_ihmaE,8211
2621
2621
  invar/node_tools/eslint-plugin/rules/shell-complexity.js,sha256=Bhc9i7ILYMNNAUvxf9l7PlwhC_Neb69Jl1nUNABu2jg,11260
@@ -2647,7 +2647,7 @@ invar/node_tools/eslint-plugin/utils/math-example.js.map,sha256=UR2zrFklTl347aXI
2647
2647
  invar/node_tools/fc-runner/bundle.js,sha256=D1wDqXYDOwWU4eqXeZdLIFvSsJ36q56Ay_ipLdklQPw,243285
2648
2648
  invar/node_tools/fc-runner/cli.d.ts,sha256=UM1WM4OKVvABXIsTHt6VHdO_oQMlgltUFV6CIqeh1B0,294
2649
2649
  invar/node_tools/fc-runner/cli.d.ts.map,sha256=-R1m4uJf2vmDZEpU7pEaib6TVjd0YuQnTQEGwkN6I9Q,117
2650
- invar/node_tools/fc-runner/cli.js,sha256=8T_YWJMmWEQmbCFsG8r4R03mi5qGpkfhitsh_5o455c,5007
2650
+ invar/node_tools/fc-runner/cli.js,sha256=Cf1c4coD3jmuE1ovP0NO2E5quWUNMgzDXK4bae1z0uk,243534
2651
2651
  invar/node_tools/fc-runner/cli.js.map,sha256=G4ecWIoU7P1ME12tM09_4N_Y6tppFNlrL3IWNPwKR2g,4195
2652
2652
  invar/node_tools/fc-runner/index.d.ts,sha256=ejHHCxatrAbDSHWuHsedGHLnpLNa6ek7rowZLdf_NiY,12615
2653
2653
  invar/node_tools/fc-runner/index.d.ts.map,sha256=MK73QKaDi8IhZ7Diphvs2sYNYbmpNIobXHbUNQBaKNg,1699
@@ -2681,7 +2681,7 @@ invar/shell/ts_compiler.py,sha256=nA8brnOhThj9J_J3vAEGjDsM4NjbWQ_eX8Yf4pHPOgk,66
2681
2681
  invar/shell/commands/__init__.py,sha256=MEkKwVyjI9DmkvBpJcuumXo2Pg_FFkfEr-Rr3nrAt7A,284
2682
2682
  invar/shell/commands/doc.py,sha256=SOLDoCXXGxx_JU0PKXlAIGEF36PzconHmmAtL-rM6D4,13819
2683
2683
  invar/shell/commands/feedback.py,sha256=lLxEeWW_71US_vlmorFrGXS8IARB9nbV6D0zruLs660,7640
2684
- invar/shell/commands/guard.py,sha256=ZuqxYkCZHoomUPuk4-HNf0bTk86il0_uRkhOTvD6T3k,24840
2684
+ invar/shell/commands/guard.py,sha256=oVx8h0YVxngfvEiuSmSuDTuXXKpzBzOHz5_5nD8_Ua4,24374
2685
2685
  invar/shell/commands/hooks.py,sha256=W-SOnT4VQyUvXwipozkJwgEYfiOJGz7wksrbcdWegUg,2356
2686
2686
  invar/shell/commands/init.py,sha256=rtoPFsfq7xRZ6lfTipWT1OejNK5wfzqu1ncXi1kizU0,23634
2687
2687
  invar/shell/commands/merge.py,sha256=nuvKo8m32-OL-SCQlS4SLKmOZxQ3qj-1nGCx1Pgzifw,8183
@@ -2778,10 +2778,10 @@ invar/templates/skills/invar-reflect/template.md,sha256=Rr5hvbllvmd8jSLf_0ZjyKt6
2778
2778
  invar/templates/skills/investigate/SKILL.md.jinja,sha256=cp6TBEixBYh1rLeeHOR1yqEnFqv1NZYePORMnavLkQI,3231
2779
2779
  invar/templates/skills/propose/SKILL.md.jinja,sha256=6BuKiCqO1AEu3VtzMHy1QWGqr_xqG9eJlhbsKT4jev4,3463
2780
2780
  invar/templates/skills/review/SKILL.md.jinja,sha256=ET5mbdSe_eKgJbi2LbgFC-z1aviKcHOBw7J5Q28fr4U,14105
2781
- invar_tools-1.17.6.dist-info/METADATA,sha256=2KB-3ghp_lXr5Tokxmprkgu4hbpDVJrCRud1tVkL2L8,28595
2782
- invar_tools-1.17.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
2783
- invar_tools-1.17.6.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
2784
- invar_tools-1.17.6.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
2785
- invar_tools-1.17.6.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
2786
- invar_tools-1.17.6.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
2787
- invar_tools-1.17.6.dist-info/RECORD,,
2781
+ invar_tools-1.17.8.dist-info/METADATA,sha256=2wbwXUo9G-81P-Riuv9WTYBY06Yiihint4wbdIvlJoE,28595
2782
+ invar_tools-1.17.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
2783
+ invar_tools-1.17.8.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
2784
+ invar_tools-1.17.8.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
2785
+ invar_tools-1.17.8.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
2786
+ invar_tools-1.17.8.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
2787
+ invar_tools-1.17.8.dist-info/RECORD,,