invar-tools 1.17.7__py3-none-any.whl → 1.17.9__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 +25 -28
- invar/shell/commands/guard.py +53 -70
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/METADATA +1 -1
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/RECORD +9 -9
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/WHEEL +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/entry_points.txt +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/licenses/LICENSE +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/licenses/LICENSE-GPL +0 -0
- {invar_tools-1.17.7.dist-info → invar_tools-1.17.9.dist-info}/licenses/NOTICE +0 -0
invar/mcp/handlers.py
CHANGED
|
@@ -11,11 +11,14 @@ import json
|
|
|
11
11
|
import subprocess
|
|
12
12
|
import sys
|
|
13
13
|
from pathlib import Path
|
|
14
|
-
from typing import Any, Literal
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
15
15
|
|
|
16
16
|
from mcp.types import TextContent
|
|
17
17
|
from returns.result import Success
|
|
18
18
|
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from mcp.server.lowlevel.server import CombinationContent
|
|
21
|
+
|
|
19
22
|
|
|
20
23
|
# @invar:allow shell_result: Pure validation helper, no I/O, returns tuple not Result
|
|
21
24
|
# @shell_complexity: Security validation requires multiple checks
|
|
@@ -59,7 +62,7 @@ def _validate_path(path: str) -> tuple[bool, str]:
|
|
|
59
62
|
# @shell_orchestration: MCP handler - subprocess is called inside
|
|
60
63
|
# @shell_complexity: Guard command with multiple optional flags
|
|
61
64
|
# @invar:allow shell_result: MCP handler for guard tool
|
|
62
|
-
async def _run_guard(args: dict[str, Any]) -> list[TextContent]:
|
|
65
|
+
async def _run_guard(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
63
66
|
"""Run invar guard command."""
|
|
64
67
|
path = args.get("path", ".")
|
|
65
68
|
is_valid, error = _validate_path(path)
|
|
@@ -88,7 +91,7 @@ async def _run_guard(args: dict[str, Any]) -> list[TextContent]:
|
|
|
88
91
|
|
|
89
92
|
# @shell_orchestration: MCP handler - subprocess is called inside
|
|
90
93
|
# @invar:allow shell_result: MCP handler for sig tool
|
|
91
|
-
async def _run_sig(args: dict[str, Any]) -> list[TextContent]:
|
|
94
|
+
async def _run_sig(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
92
95
|
"""Run invar sig command."""
|
|
93
96
|
target = args.get("target", "")
|
|
94
97
|
if not target:
|
|
@@ -106,7 +109,7 @@ async def _run_sig(args: dict[str, Any]) -> list[TextContent]:
|
|
|
106
109
|
|
|
107
110
|
# @shell_orchestration: MCP handler - subprocess is called inside
|
|
108
111
|
# @invar:allow shell_result: MCP handler for map tool
|
|
109
|
-
async def _run_map(args: dict[str, Any]) -> list[TextContent]:
|
|
112
|
+
async def _run_map(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
110
113
|
"""Run invar map command."""
|
|
111
114
|
path = args.get("path", ".")
|
|
112
115
|
is_valid, error = _validate_path(path)
|
|
@@ -125,7 +128,7 @@ async def _run_map(args: dict[str, Any]) -> list[TextContent]:
|
|
|
125
128
|
|
|
126
129
|
# @shell_orchestration: MCP handler - orchestrates refs command execution
|
|
127
130
|
# @invar:allow shell_result: MCP handler for refs tool
|
|
128
|
-
async def _run_refs(args: dict[str, Any]) -> list[TextContent]:
|
|
131
|
+
async def _run_refs(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
129
132
|
"""Run invar refs command.
|
|
130
133
|
|
|
131
134
|
DX-78: Find all references to a symbol.
|
|
@@ -155,7 +158,7 @@ async def _run_refs(args: dict[str, Any]) -> list[TextContent]:
|
|
|
155
158
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
156
159
|
# @shell_complexity: MCP input validation + result handling
|
|
157
160
|
# @invar:allow shell_result: MCP handler for doc_toc tool
|
|
158
|
-
async def _run_doc_toc(args: dict[str, Any]) -> list[TextContent]:
|
|
161
|
+
async def _run_doc_toc(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
159
162
|
"""Run invar_doc_toc - extract document structure."""
|
|
160
163
|
from dataclasses import asdict
|
|
161
164
|
|
|
@@ -203,7 +206,7 @@ def _section_to_dict(section: Any) -> dict[str, Any]:
|
|
|
203
206
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
204
207
|
# @shell_complexity: MCP input validation + result handling
|
|
205
208
|
# @invar:allow shell_result: MCP handler for doc_read tool
|
|
206
|
-
async def _run_doc_read(args: dict[str, Any]) -> list[TextContent]:
|
|
209
|
+
async def _run_doc_read(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
207
210
|
"""Run invar_doc_read - read a specific section."""
|
|
208
211
|
from invar.shell.doc_tools import read_section
|
|
209
212
|
|
|
@@ -232,7 +235,7 @@ async def _run_doc_read(args: dict[str, Any]) -> list[TextContent]:
|
|
|
232
235
|
|
|
233
236
|
# @shell_complexity: Multiple arg validation branches + error handling
|
|
234
237
|
# @invar:allow shell_result: MCP handler for doc_read_many tool
|
|
235
|
-
async def _run_doc_read_many(args: dict[str, Any]) -> list[TextContent]:
|
|
238
|
+
async def _run_doc_read_many(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
236
239
|
"""Run invar_doc_read_many - read multiple sections."""
|
|
237
240
|
from invar.shell.doc_tools import read_sections_batch
|
|
238
241
|
|
|
@@ -264,7 +267,7 @@ async def _run_doc_read_many(args: dict[str, Any]) -> list[TextContent]:
|
|
|
264
267
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
265
268
|
# @shell_complexity: MCP input validation + result handling
|
|
266
269
|
# @invar:allow shell_result: MCP handler for doc_find tool
|
|
267
|
-
async def _run_doc_find(args: dict[str, Any]) -> list[TextContent]:
|
|
270
|
+
async def _run_doc_find(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
268
271
|
"""Run invar_doc_find - find sections matching pattern."""
|
|
269
272
|
from invar.shell.doc_tools import find_sections
|
|
270
273
|
|
|
@@ -308,7 +311,7 @@ async def _run_doc_find(args: dict[str, Any]) -> list[TextContent]:
|
|
|
308
311
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
309
312
|
# @shell_complexity: MCP input validation + result handling
|
|
310
313
|
# @invar:allow shell_result: MCP handler for doc_replace tool
|
|
311
|
-
async def _run_doc_replace(args: dict[str, Any]) -> list[TextContent]:
|
|
314
|
+
async def _run_doc_replace(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
312
315
|
"""Run invar_doc_replace - replace section content."""
|
|
313
316
|
from invar.shell.doc_tools import replace_section_content
|
|
314
317
|
|
|
@@ -342,7 +345,7 @@ async def _run_doc_replace(args: dict[str, Any]) -> list[TextContent]:
|
|
|
342
345
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
343
346
|
# @shell_complexity: MCP input validation + result handling
|
|
344
347
|
# @invar:allow shell_result: MCP handler for doc_insert tool
|
|
345
|
-
async def _run_doc_insert(args: dict[str, Any]) -> list[TextContent]:
|
|
348
|
+
async def _run_doc_insert(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
346
349
|
"""Run invar_doc_insert - insert content relative to section."""
|
|
347
350
|
from invar.shell.doc_tools import insert_section_content
|
|
348
351
|
|
|
@@ -382,7 +385,7 @@ async def _run_doc_insert(args: dict[str, Any]) -> list[TextContent]:
|
|
|
382
385
|
# @shell_orchestration: MCP handler - calls shell layer directly
|
|
383
386
|
# @shell_complexity: MCP input validation + result handling
|
|
384
387
|
# @invar:allow shell_result: MCP handler for doc_delete tool
|
|
385
|
-
async def _run_doc_delete(args: dict[str, Any]) -> list[TextContent]:
|
|
388
|
+
async def _run_doc_delete(args: dict[str, Any]) -> list[TextContent] | CombinationContent:
|
|
386
389
|
"""Run invar_doc_delete - delete a section."""
|
|
387
390
|
from invar.shell.doc_tools import delete_section_content
|
|
388
391
|
|
|
@@ -411,13 +414,11 @@ async def _run_doc_delete(args: dict[str, Any]) -> list[TextContent]:
|
|
|
411
414
|
|
|
412
415
|
# @shell_complexity: Command execution with error handling branches
|
|
413
416
|
# @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
|
-
"""
|
|
417
|
+
async def _execute_command(
|
|
418
|
+
cmd: list[str],
|
|
419
|
+
timeout: int = 600,
|
|
420
|
+
) -> list[TextContent] | CombinationContent:
|
|
421
|
+
"""Execute a command and return result."""
|
|
421
422
|
try:
|
|
422
423
|
result = subprocess.run(
|
|
423
424
|
cmd,
|
|
@@ -426,18 +427,14 @@ async def _execute_command(cmd: list[str], timeout: int = 600) -> list[TextConte
|
|
|
426
427
|
timeout=timeout,
|
|
427
428
|
)
|
|
428
429
|
|
|
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
430
|
try:
|
|
435
431
|
parsed = json.loads(result.stdout)
|
|
436
|
-
|
|
432
|
+
return ([TextContent(type="text", text=json.dumps(parsed, indent=2))], parsed)
|
|
437
433
|
except json.JSONDecodeError:
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
434
|
+
output = result.stdout
|
|
435
|
+
if result.stderr:
|
|
436
|
+
output += f"\n\nStderr:\n{result.stderr}"
|
|
437
|
+
return [TextContent(type="text", text=output)]
|
|
441
438
|
|
|
442
439
|
except subprocess.TimeoutExpired:
|
|
443
440
|
return [TextContent(type="text", text=f"Error: Command timed out ({timeout}s)")]
|
invar/shell/commands/guard.py
CHANGED
|
@@ -6,7 +6,6 @@ Shell module: handles user interaction and file I/O.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
import os
|
|
10
9
|
from pathlib import Path
|
|
11
10
|
|
|
12
11
|
import typer
|
|
@@ -14,13 +13,6 @@ from returns.result import Failure, Result, Success
|
|
|
14
13
|
from rich.console import Console
|
|
15
14
|
from rich.table import Table
|
|
16
15
|
|
|
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
16
|
from invar import __version__
|
|
25
17
|
from invar.core.models import GuardReport, RuleConfig
|
|
26
18
|
from invar.core.rules import check_all_rules
|
|
@@ -95,12 +87,14 @@ def _scan_and_check(
|
|
|
95
87
|
for rule, reason, line in extract_escape_hatches(file_info.source):
|
|
96
88
|
all_escapes.append((file_info.path, rule, reason))
|
|
97
89
|
# DX-66: Add to escape hatch summary
|
|
98
|
-
report.escape_hatches.add(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
report.escape_hatches.add(
|
|
91
|
+
EscapeHatchDetail(
|
|
92
|
+
file=file_info.path,
|
|
93
|
+
line=line,
|
|
94
|
+
rule=rule,
|
|
95
|
+
reason=reason,
|
|
96
|
+
)
|
|
97
|
+
)
|
|
104
98
|
|
|
105
99
|
# DX-22: Check project-level complexity debt (Fix-or-Explain enforcement)
|
|
106
100
|
for debt_violation in check_complexity_debt(
|
|
@@ -115,6 +109,10 @@ def _scan_and_check(
|
|
|
115
109
|
return Success(report)
|
|
116
110
|
|
|
117
111
|
|
|
112
|
+
def _determine_output_mode(human: bool, agent: bool = False, json_output: bool = False) -> bool:
|
|
113
|
+
return not human
|
|
114
|
+
|
|
115
|
+
|
|
118
116
|
# @invar:allow entry_point_too_thick: Main CLI entry point, orchestrates all verification phases
|
|
119
117
|
@app.command()
|
|
120
118
|
def guard(
|
|
@@ -133,7 +131,7 @@ def guard(
|
|
|
133
131
|
False, "--static", help="Static analysis only, skip all runtime tests"
|
|
134
132
|
),
|
|
135
133
|
human: bool = typer.Option(
|
|
136
|
-
False, "--human", help="Force human-readable output (
|
|
134
|
+
False, "--human", help="Force Rich human-readable output (opt-in, default is JSON)"
|
|
137
135
|
),
|
|
138
136
|
# DX-26: Deprecated flags kept for backward compatibility
|
|
139
137
|
no_strict_pure: bool = typer.Option(
|
|
@@ -192,23 +190,12 @@ def guard(
|
|
|
192
190
|
ts_result = run_typescript_guard(path if path.is_dir() else find_project_root(path))
|
|
193
191
|
match ts_result:
|
|
194
192
|
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}")
|
|
193
|
+
import json as json_mod
|
|
194
|
+
|
|
195
|
+
from invar.shell.prove.guard_ts import format_typescript_guard_v2
|
|
196
|
+
|
|
197
|
+
output = format_typescript_guard_v2(result)
|
|
198
|
+
console.print(json_mod.dumps(output, indent=2))
|
|
212
199
|
raise typer.Exit(0 if result.status == "passed" else 1)
|
|
213
200
|
case Failure(err):
|
|
214
201
|
console.print(f"[red]Error:[/red] {err}")
|
|
@@ -295,6 +282,7 @@ def guard(
|
|
|
295
282
|
run_pattern_detection,
|
|
296
283
|
suggestions_to_violations,
|
|
297
284
|
)
|
|
285
|
+
|
|
298
286
|
# Run pattern detection on checked files
|
|
299
287
|
files_to_check = list(only_files) if only_files else None
|
|
300
288
|
pattern_result = run_pattern_detection(path, files_to_check)
|
|
@@ -331,6 +319,7 @@ def guard(
|
|
|
331
319
|
# DX-37: Check coverage availability if requested
|
|
332
320
|
if coverage:
|
|
333
321
|
from invar.shell.coverage import check_coverage_available
|
|
322
|
+
|
|
334
323
|
cov_check = check_coverage_available()
|
|
335
324
|
if isinstance(cov_check, Failure):
|
|
336
325
|
console.print(f"[yellow]Warning:[/yellow] {cov_check.failure()}")
|
|
@@ -342,14 +331,19 @@ def guard(
|
|
|
342
331
|
|
|
343
332
|
# Phase 1: Doctests (DX-37: with optional coverage)
|
|
344
333
|
doctest_passed, doctest_output, doctest_coverage = run_doctests_phase(
|
|
345
|
-
checked_files,
|
|
334
|
+
checked_files,
|
|
335
|
+
explain,
|
|
336
|
+
timeout=config.timeout_doctest,
|
|
346
337
|
collect_coverage=coverage,
|
|
347
338
|
)
|
|
348
339
|
|
|
349
340
|
# Phase 2: CrossHair symbolic verification
|
|
350
341
|
# Note: CrossHair uses subprocess + symbolic execution, coverage not applicable
|
|
351
342
|
crosshair_passed, crosshair_output = run_crosshair_phase(
|
|
352
|
-
path,
|
|
343
|
+
path,
|
|
344
|
+
checked_files,
|
|
345
|
+
doctest_passed,
|
|
346
|
+
static_exit_code,
|
|
353
347
|
changed_mode=changed,
|
|
354
348
|
timeout=config.timeout_crosshair,
|
|
355
349
|
per_condition_timeout=config.timeout_crosshair_per_condition,
|
|
@@ -357,7 +351,9 @@ def guard(
|
|
|
357
351
|
|
|
358
352
|
# Phase 3: Hypothesis property tests (DX-37: with optional coverage)
|
|
359
353
|
property_passed, property_output, property_coverage = run_property_tests_phase(
|
|
360
|
-
checked_files,
|
|
354
|
+
checked_files,
|
|
355
|
+
doctest_passed,
|
|
356
|
+
static_exit_code,
|
|
361
357
|
collect_coverage=coverage,
|
|
362
358
|
)
|
|
363
359
|
elif verification_level == VerificationLevel.STATIC:
|
|
@@ -382,20 +378,31 @@ def guard(
|
|
|
382
378
|
if property_coverage and property_coverage.get("collected"):
|
|
383
379
|
coverage_output["phases_tracked"].append("hypothesis")
|
|
384
380
|
if "overall_branch_coverage" in property_coverage:
|
|
385
|
-
coverage_output["overall_branch_coverage"] = property_coverage[
|
|
381
|
+
coverage_output["overall_branch_coverage"] = property_coverage[
|
|
382
|
+
"overall_branch_coverage"
|
|
383
|
+
]
|
|
386
384
|
|
|
387
385
|
# DX-26: Unified output (agent JSON or human Rich)
|
|
388
386
|
if use_agent_output:
|
|
389
387
|
output_agent(
|
|
390
|
-
report,
|
|
388
|
+
report,
|
|
389
|
+
strict,
|
|
390
|
+
doctest_passed,
|
|
391
|
+
doctest_output,
|
|
392
|
+
crosshair_output,
|
|
393
|
+
level_name,
|
|
391
394
|
property_output=property_output,
|
|
392
395
|
coverage_data=coverage_output, # DX-37
|
|
393
396
|
)
|
|
394
397
|
else:
|
|
395
398
|
output_rich(report, config.strict_pure, changed, pedantic, explain, static)
|
|
396
399
|
output_verification_status(
|
|
397
|
-
verification_level,
|
|
398
|
-
|
|
400
|
+
verification_level,
|
|
401
|
+
static_exit_code,
|
|
402
|
+
doctest_passed,
|
|
403
|
+
doctest_output,
|
|
404
|
+
crosshair_output,
|
|
405
|
+
explain,
|
|
399
406
|
property_output=property_output,
|
|
400
407
|
strict=strict,
|
|
401
408
|
)
|
|
@@ -405,7 +412,9 @@ def guard(
|
|
|
405
412
|
overall = coverage_output.get("overall_branch_coverage", 0.0)
|
|
406
413
|
console.print(f"\n[bold]Coverage Analysis[/bold] ({' + '.join(phases)})")
|
|
407
414
|
console.print(f" Overall branch coverage: {overall}%")
|
|
408
|
-
console.print(
|
|
415
|
+
console.print(
|
|
416
|
+
" [dim]Note: CrossHair uses symbolic execution; coverage not applicable.[/dim]"
|
|
417
|
+
)
|
|
409
418
|
|
|
410
419
|
# Exit with combined status
|
|
411
420
|
all_passed = doctest_passed and crosshair_passed and property_passed
|
|
@@ -413,28 +422,6 @@ def guard(
|
|
|
413
422
|
raise typer.Exit(final_exit)
|
|
414
423
|
|
|
415
424
|
|
|
416
|
-
# @shell_orchestration: Output mode decision helper for CLI
|
|
417
|
-
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).
|
|
419
|
-
|
|
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 flags → still work for backward compat
|
|
425
|
-
"""
|
|
426
|
-
# --human flag always forces human output
|
|
427
|
-
if human:
|
|
428
|
-
return False # use_agent = False
|
|
429
|
-
|
|
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
|
|
436
|
-
|
|
437
|
-
|
|
438
425
|
def _show_verification_level(verification_level) -> None:
|
|
439
426
|
"""Show verification level in human-readable format.
|
|
440
427
|
|
|
@@ -464,8 +451,7 @@ def map_command(
|
|
|
464
451
|
"""Generate symbol map with reference counts."""
|
|
465
452
|
from invar.shell.commands.perception import run_map
|
|
466
453
|
|
|
467
|
-
|
|
468
|
-
use_json = json_output or _detect_agent_mode()
|
|
454
|
+
use_json = True
|
|
469
455
|
result = run_map(path, top, use_json)
|
|
470
456
|
if isinstance(result, Failure):
|
|
471
457
|
console.print(f"[red]Error:[/red] {result.failure()}")
|
|
@@ -480,8 +466,7 @@ def sig_command(
|
|
|
480
466
|
"""Extract signatures from a file or symbol."""
|
|
481
467
|
from invar.shell.commands.perception import run_sig
|
|
482
468
|
|
|
483
|
-
|
|
484
|
-
use_json = json_output or _detect_agent_mode()
|
|
469
|
+
use_json = True
|
|
485
470
|
result = run_sig(target, use_json)
|
|
486
471
|
if isinstance(result, Failure):
|
|
487
472
|
console.print(f"[red]Error:[/red] {result.failure()}")
|
|
@@ -504,8 +489,7 @@ def refs_command(
|
|
|
504
489
|
"""
|
|
505
490
|
from invar.shell.commands.perception import run_refs
|
|
506
491
|
|
|
507
|
-
|
|
508
|
-
use_json = json_output or _detect_agent_mode()
|
|
492
|
+
use_json = True
|
|
509
493
|
result = run_refs(target, use_json)
|
|
510
494
|
if isinstance(result, Failure):
|
|
511
495
|
console.print(f"[red]Error:[/red] {result.failure()}")
|
|
@@ -529,8 +513,7 @@ def rules(
|
|
|
529
513
|
|
|
530
514
|
from invar.core.rule_meta import RULE_META, RuleCategory, get_rules_by_category
|
|
531
515
|
|
|
532
|
-
|
|
533
|
-
use_json = json_output or _detect_agent_mode()
|
|
516
|
+
use_json = True
|
|
534
517
|
|
|
535
518
|
# Filter by category if specified
|
|
536
519
|
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.9
|
|
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=3khWBATWxV4TwHPm6Gnr9pWfGaPyxf5p8yR-pnJhDtg,16756
|
|
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=6Ik3DJ8x6f8ZE-Y9UnzZXf2Lo2e3ZgiWUmN08cRldyE,23264
|
|
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.9.dist-info/METADATA,sha256=OvB2f3yrJg-G-p5y5DRWqtFxuqI2g2gKHnuh2rJWnH4,28595
|
|
2782
|
+
invar_tools-1.17.9.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
2783
|
+
invar_tools-1.17.9.dist-info/entry_points.txt,sha256=RwH_EhqgtFPsnO6RcrwrAb70Zyfb8Mh6uUtztWnUxGk,102
|
|
2784
|
+
invar_tools-1.17.9.dist-info/licenses/LICENSE,sha256=qeFksp4H4kfTgQxPCIu3OdagXyiZcgBlVfsQ6M5oFyk,10767
|
|
2785
|
+
invar_tools-1.17.9.dist-info/licenses/LICENSE-GPL,sha256=IvZfC6ZbP7CLjytoHVzvpDZpD-Z3R_qa1GdMdWlWQ6Q,35157
|
|
2786
|
+
invar_tools-1.17.9.dist-info/licenses/NOTICE,sha256=joEyMyFhFY8Vd8tTJ-a3SirI0m2Sd0WjzqYt3sdcglc,2561
|
|
2787
|
+
invar_tools-1.17.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|