File size: 4,451 Bytes
4d393e8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
"""
`dw rules` subcommands.
Manages dynamic validation policy rules (linter rules) on the workspace.
"""
from __future__ import annotations

import json
from typing import Optional
import typer
from rich.table import Table

from diffweave.cli.config import get_active_workspace
from diffweave.cli.output import print_success, print_error, print_info, print_json, console
from diffweave.mcp.client import DiffWeaveMCPClient

rules_app = typer.Typer(name="rules", help="Manage validation policy rules for workspace.")


@rules_app.command("list")
def list_rules_cmd(
    workspace_id: Optional[str] = typer.Option(None, "--workspace", "-w", help="Workspace UUID override"),
    as_json: bool = typer.Option(False, "--json", help="Output machine-readable JSON"),
):
    """List all validation policy rules configured for the workspace."""
    try:
        active_ws_id = get_active_workspace(workspace_id)
    except Exception as e:
        print_error(str(e))
        raise typer.Exit(code=1)

    client = DiffWeaveMCPClient()
    try:
        rules = client.call_tool_sync("list_rules", {"workspace_id": active_ws_id})
    except Exception as e:
        print_error(f"Failed to list rules: {e}")
        raise typer.Exit(code=1)

    if as_json:
        print_json(rules)
        return

    if not rules:
        console.print("[dim]No policy rules configured. Use 'dw rules add' to create one.[/dim]")
        return

    table = Table(title="Workspace Policy Rules", header_style="bold cyan")
    table.add_column("Rule ID", style="dim")
    table.add_column("Name", style="bold white")
    table.add_column("Operator", style="cyan")
    table.add_column("Status", style="bold")
    table.add_column("Configuration", style="dim")

    for r in rules:
        status_styled = "[green]ENABLED[/green]" if r.get("enabled") else "[yellow]DISABLED[/yellow]"
        table.add_row(
            r.get("id", "")[:8],
            r.get("name", "Unnamed"),
            r.get("operator") or "n/a",
            status_styled,
            json.dumps(r.get("configuration") or {}),
        )

    console.print(table)


@rules_app.command("enable")
def enable_rule_cmd(rule_id: str = typer.Argument(..., help="Rule UUID to enable")):
    """Enable a validation rule."""
    client = DiffWeaveMCPClient()
    try:
        res = client.call_tool_sync("enable_rule", {"rule_id": rule_id})
        print_success(f"Rule '{res.get('name')}' ({rule_id[:8]}) is now ENABLED.")
    except Exception as e:
        print_error(f"Failed to enable rule: {e}")
        raise typer.Exit(code=1)


@rules_app.command("disable")
def disable_rule_cmd(rule_id: str = typer.Argument(..., help="Rule UUID to disable")):
    """Disable a validation rule without deleting it."""
    client = DiffWeaveMCPClient()
    try:
        res = client.call_tool_sync("disable_rule", {"rule_id": rule_id})
        print_info(f"Rule '{res.get('name')}' ({rule_id[:8]}) is now DISABLED.")
    except Exception as e:
        print_error(f"Failed to disable rule: {e}")
        raise typer.Exit(code=1)


@rules_app.command("add")
def add_rule_cmd(
    name: str = typer.Argument(..., help="Human-readable rule name"),
    operator: str = typer.Option("min_confidence", "--operator", "-o", help="Rule operator: min_confidence, required_evidence, allowed_proposal_types"),
    threshold: float = typer.Option(0.85, "--threshold", "-t", help="Threshold for min_confidence operator"),
    workspace_id: Optional[str] = typer.Option(None, "--workspace", "-w", help="Workspace UUID override"),
):
    """Add a new validation rule to the workspace."""
    try:
        active_ws_id = get_active_workspace(workspace_id)
    except Exception as e:
        print_error(str(e))
        raise typer.Exit(code=1)

    client = DiffWeaveMCPClient()
    config = {}
    if operator == "min_confidence":
        config = {"value": threshold}
    elif operator == "allowed_proposal_types":
        config = {"values": ["CREATE", "UPDATE"]}

    try:
        res = client.call_tool_sync(
            "create_rule",
            {
                "workspace_id": active_ws_id,
                "name": name,
                "operator": operator,
                "configuration": config,
            },
        )
        print_success(f"Created rule [bold]{res.get('name')}[/bold] (ID: {res.get('id')[:8]})")
    except Exception as e:
        print_error(f"Failed to create rule: {e}")
        raise typer.Exit(code=1)