invar-tools 1.17.7__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.
- invar/mcp/handlers.py +23 -28
- invar/shell/commands/guard.py +69 -59
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/METADATA +1 -1
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/RECORD +9 -9
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/WHEEL +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/entry_points.txt +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/licenses/LICENSE +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/licenses/LICENSE-GPL +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.8.dist-info}/licenses/NOTICE +0 -0
invar/mcp/handlers.py
CHANGED
|
@@ -13,6 +13,7 @@ import sys
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any, Literal
|
|
15
15
|
|
|
16
|
+
from mcp.server.lowlevel.server import StructuredContent, CombinationContent
|
|
16
17
|
from mcp.types import TextContent
|
|
17
18
|
from returns.result import Success
|
|
18
19
|
|
|
@@ -59,7 +60,7 @@ def _validate_path(path: str) -> tuple[bool, str]:
|
|
|
59
60
|
# @shell_orchestration: MCP handler - subprocess is called inside
|
|
60
61
|
# @shell_complexity: Guard command with multiple optional flags
|
|
61
62
|
# @invar:allow shell_result: MCP handler for guard tool
|
|
62
|
-
async def _run_guard(args: dict[str, Any]) -> list[TextContent]:
|
|
63
|
+
async def _run_guard(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
63
64
|
"""Run invar guard command."""
|
|
64
65
|
path = args.get("path", ".")
|
|
65
66
|
is_valid, error = _validate_path(path)
|
|
@@ -88,7 +89,7 @@ async def _run_guard(args: dict[str, Any]) -> list[TextContent]:
|
|
|
88
89
|
|
|
89
90
|
# @shell_orchestration: MCP handler - subprocess is called inside
|
|
90
91
|
# @invar:allow shell_result: MCP handler for sig tool
|
|
91
|
-
async def _run_sig(args: dict[str, Any]) -> list[TextContent]:
|
|
92
|
+
async def _run_sig(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
92
93
|
"""Run invar sig command."""
|
|
93
94
|
target = args.get("target", "")
|
|
94
95
|
if not target:
|
|
@@ -106,7 +107,7 @@ async def _run_sig(args: dict[str, Any]) -> list[TextContent]:
|
|
|
106
107
|
|
|
107
108
|
# @shell_orchestration: MCP handler - subprocess is called inside
|
|
108
109
|
# @invar:allow shell_result: MCP handler for map tool
|
|
109
|
-
async def _run_map(args: dict[str, Any]) -> list[TextContent]:
|
|
110
|
+
async def _run_map(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
110
111
|
"""Run invar map command."""
|
|
111
112
|
path = args.get("path", ".")
|
|
112
113
|
is_valid, error = _validate_path(path)
|
|
@@ -125,7 +126,7 @@ async def _run_map(args: dict[str, Any]) -> list[TextContent]:
|
|
|
125
126
|
|
|
126
127
|
# @shell_orchestration: MCP handler - orchestrates refs command execution
|
|
127
128
|
# @invar:allow shell_result: MCP handler for refs tool
|
|
128
|
-
async def _run_refs(args: dict[str, Any]) -> list[TextContent]:
|
|
129
|
+
async def _run_refs(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
129
130
|
"""Run invar refs command.
|
|
130
131
|
|
|
131
132
|
DX-78: Find all references to a symbol.
|
|
@@ -155,7 +156,7 @@ async def _run_refs(args: dict[str, Any]) -> list[TextContent]:
|
|
|
155
156
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
156
157
|
# @shell_complexity: MCP input validation + result handling
|
|
157
158
|
# @invar:allow shell_result: MCP handler for doc_toc tool
|
|
158
|
-
async def _run_doc_toc(args: dict[str, Any]) -> list[TextContent]:
|
|
159
|
+
async def _run_doc_toc(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
159
160
|
"""Run invar_doc_toc - extract document structure."""
|
|
160
161
|
from dataclasses import asdict
|
|
161
162
|
|
|
@@ -203,7 +204,7 @@ def _section_to_dict(section: Any) -> dict[str, Any]:
|
|
|
203
204
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
204
205
|
# @shell_complexity: MCP input validation + result handling
|
|
205
206
|
# @invar:allow shell_result: MCP handler for doc_read tool
|
|
206
|
-
async def _run_doc_read(args: dict[str, Any]) -> list[TextContent]:
|
|
207
|
+
async def _run_doc_read(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
207
208
|
"""Run invar_doc_read - read a specific section."""
|
|
208
209
|
from invar.shell.doc_tools import read_section
|
|
209
210
|
|
|
@@ -232,7 +233,7 @@ async def _run_doc_read(args: dict[str, Any]) -> list[TextContent]:
|
|
|
232
233
|
|
|
233
234
|
# @shell_complexity: Multiple arg validation branches + error handling
|
|
234
235
|
# @invar:allow shell_result: MCP handler for doc_read_many tool
|
|
235
|
-
async def _run_doc_read_many(args: dict[str, Any]) -> list[TextContent]:
|
|
236
|
+
async def _run_doc_read_many(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
236
237
|
"""Run invar_doc_read_many - read multiple sections."""
|
|
237
238
|
from invar.shell.doc_tools import read_sections_batch
|
|
238
239
|
|
|
@@ -264,7 +265,7 @@ async def _run_doc_read_many(args: dict[str, Any]) -> list[TextContent]:
|
|
|
264
265
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
265
266
|
# @shell_complexity: MCP input validation + result handling
|
|
266
267
|
# @invar:allow shell_result: MCP handler for doc_find tool
|
|
267
|
-
async def _run_doc_find(args: dict[str, Any]) -> list[TextContent]:
|
|
268
|
+
async def _run_doc_find(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
268
269
|
"""Run invar_doc_find - find sections matching pattern."""
|
|
269
270
|
from invar.shell.doc_tools import find_sections
|
|
270
271
|
|
|
@@ -308,7 +309,7 @@ async def _run_doc_find(args: dict[str, Any]) -> list[TextContent]:
|
|
|
308
309
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
309
310
|
# @shell_complexity: MCP input validation + result handling
|
|
310
311
|
# @invar:allow shell_result: MCP handler for doc_replace tool
|
|
311
|
-
async def _run_doc_replace(args: dict[str, Any]) -> list[TextContent]:
|
|
312
|
+
async def _run_doc_replace(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
312
313
|
"""Run invar_doc_replace - replace section content."""
|
|
313
314
|
from invar.shell.doc_tools import replace_section_content
|
|
314
315
|
|
|
@@ -342,7 +343,7 @@ async def _run_doc_replace(args: dict[str, Any]) -> list[TextContent]:
|
|
|
342
343
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
343
344
|
# @shell_complexity: MCP input validation + result handling
|
|
344
345
|
# @invar:allow shell_result: MCP handler for doc_insert tool
|
|
345
|
-
async def _run_doc_insert(args: dict[str, Any]) -> list[TextContent]:
|
|
346
|
+
async def _run_doc_insert(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
346
347
|
"""Run invar_doc_insert - insert content relative to section."""
|
|
347
348
|
from invar.shell.doc_tools import insert_section_content
|
|
348
349
|
|
|
@@ -382,7 +383,7 @@ async def _run_doc_insert(args: dict[str, Any]) -> list[TextContent]:
|
|
|
382
383
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
383
384
|
# @shell_complexity: MCP input validation + result handling
|
|
384
385
|
# @invar:allow shell_result: MCP handler for doc_delete tool
|
|
385
|
-
async def _run_doc_delete(args: dict[str, Any]) -> list[TextContent]:
|
|
386
|
+
async def _run_doc_delete(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
386
387
|
"""Run invar_doc_delete - delete a section."""
|
|
387
388
|
from invar.shell.doc_tools import delete_section_content
|
|
388
389
|
|
|
@@ -411,13 +412,11 @@ async def _run_doc_delete(args: dict[str, Any]) -> list[TextContent]:
|
|
|
411
412
|
|
|
412
413
|
# @shell_complexity: Command execution with error handling branches
|
|
413
414
|
# @invar:allow shell_result: MCP subprocess wrapper utility
|
|
414
|
-
async def _execute_command(
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
timeout: Maximum time in seconds (default: 600, accommodates full Guard cycle)
|
|
420
|
-
"""
|
|
415
|
+
async def _execute_command(
|
|
416
|
+
cmd: list[str],
|
|
417
|
+
timeout: int = 600,
|
|
418
|
+
) -> list[TextContent] | CombinationContent:
|
|
419
|
+
"""Execute a command and return result."""
|
|
421
420
|
try:
|
|
422
421
|
result = subprocess.run(
|
|
423
422
|
cmd,
|
|
@@ -426,20 +425,16 @@ async def _execute_command(cmd: list[str], timeout: int = 600) -> list[TextConte
|
|
|
426
425
|
timeout=timeout,
|
|
427
426
|
)
|
|
428
427
|
|
|
429
|
-
output = result.stdout
|
|
430
|
-
if result.stderr:
|
|
431
|
-
output += f"\n\nStderr:\n{result.stderr}"
|
|
432
|
-
|
|
433
|
-
# Try to parse as JSON for better formatting
|
|
434
428
|
try:
|
|
435
429
|
parsed = json.loads(result.stdout)
|
|
436
|
-
|
|
430
|
+
return ([TextContent(type="text", text=json.dumps(parsed, indent=2))], parsed)
|
|
437
431
|
except json.JSONDecodeError:
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
432
|
+
output = result.stdout
|
|
433
|
+
if result.stderr:
|
|
434
|
+
output += f"\n\nStderr:\n{result.stderr}"
|
|
435
|
+
return [TextContent(type="text", text=output)]
|
|
441
436
|
|
|
442
437
|
except subprocess.TimeoutExpired:
|
|
443
|
-
return [TextContent(type="text", text=f"Error: Command timed out ({timeout}s
|
|
438
|
+
return [TextContent(type="text", text=f"Error: Command timed out ({timeout}s")]
|
|
444
439
|
except Exception as e:
|
|
445
440
|
return [TextContent(type="text", text=f"Error: {e}")]
|
invar/shell/commands/guard.py
CHANGED
|
@@ -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(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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 (
|
|
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
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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[
|
|
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,
|
|
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,
|
|
398
|
-
|
|
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(
|
|
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 (
|
|
425
|
+
"""Determine if agent JSON output should be used (Agent First).
|
|
419
426
|
|
|
420
|
-
|
|
421
|
-
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
-
|
|
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 flag → human 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
|
|
435
|
+
# --human flag forces human output (priority highest)
|
|
427
436
|
if human:
|
|
428
437
|
return False # use_agent = False
|
|
429
438
|
|
|
430
|
-
#
|
|
431
|
-
|
|
432
|
-
|
|
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
|
-
#
|
|
468
|
-
|
|
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
|
-
#
|
|
484
|
-
|
|
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
|
-
#
|
|
508
|
-
|
|
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
|
-
#
|
|
533
|
-
|
|
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.
|
|
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=
|
|
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
|
|
@@ -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=
|
|
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.
|
|
2782
|
-
invar_tools-1.17.
|
|
2783
|
-
invar_tools-1.17.
|
|
2784
|
-
invar_tools-1.17.
|
|
2785
|
-
invar_tools-1.17.
|
|
2786
|
-
invar_tools-1.17.
|
|
2787
|
-
invar_tools-1.17.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|