1313- policy: Manage policies
1414"""
1515
16- import logging
1716import json
17+ import logging
1818import os
19- import yaml
2019import re
2120from pathlib import Path
22- from typing import Optional
2321
2422import click
23+ import yaml
24+ from rich import box
2525from rich .console import Console
26- from rich .table import Table
2726from rich .panel import Panel
28- from rich import box
27+ from rich . table import Table
2928
3029console = Console ()
3130logger = logging .getLogger (__name__ )
3231
3332
34- def handle_error (e : Exception , output_json : bool = False , custom_msg : Optional [ str ] = None ):
33+ def handle_error (e : Exception , output_json : bool = False , custom_msg : str | None = None ):
3534 """Centralized error handler for CLI commands."""
3635 is_known = isinstance (e , (ImportError , ValueError , KeyError , PermissionError , FileNotFoundError , yaml .YAMLError , json .JSONDecodeError ))
37-
36+
3837 # Sanitize message: use custom msg if provided, else generic for unknown errors
3938 if custom_msg :
4039 err_msg = custom_msg
@@ -43,10 +42,10 @@ def handle_error(e: Exception, output_json: bool = False, custom_msg: Optional[s
4342 err_msg = "A validation, permission, or configuration error occurred."
4443 else :
4544 err_msg = "An unexpected internal error occurred."
46-
45+
4746 # Log the full details for debugging (not shown to user unless DEBUG is on)
4847 logger .error (f"CLI Error: { e } " , exc_info = True )
49-
48+
5049 if output_json :
5150 status = "error"
5251 type_field = "ValidationError" if is_known else "InternalError"
@@ -434,7 +433,7 @@ def policy(policy_file: str, validate: bool, output_json: bool):
434433 else :
435434 policy_data = json .load (f )
436435
437- from agentmesh .governance import PolicyEngine , Policy
436+ from agentmesh .governance import Policy , PolicyEngine
438437 engine = PolicyEngine ()
439438
440439 policies = policy_data .get ("policies" , [])
@@ -484,7 +483,7 @@ def audit(agent: str, limit: int, fmt: str, output_json: bool):
484483 entries = [e for e in entries if e ["agent" ].lower () == agent ]
485484
486485 entries = entries [:limit ]
487-
486+
488487 # Sanitize entries for JSON output with strict key whitelisting and value validation
489488 allowed_keys = {"timestamp" , "agent" , "action" , "status" }
490489 sanitized_entries = []
@@ -539,12 +538,12 @@ def audit(agent: str, limit: int, fmt: str, output_json: bool):
539538def init_integration (claude : bool , config_path : str , backup : bool ):
540539 """
541540 Initialize AgentMesh integration with existing tools.
542-
541+
543542 Examples:
544-
543+
545544 # Setup Claude Desktop to use AgentMesh proxy
546545 agentmesh init-integration --claude
547-
546+
548547 # Specify custom config path
549548 agentmesh init-integration --claude --config-path ~/custom/config.json
550549 """
@@ -554,29 +553,29 @@ def init_integration(claude: bool, config_path: str, backup: bool):
554553 console .print ("[yellow]Please specify an integration type (e.g., --claude)[/yellow]" )
555554
556555
557- def _init_claude_integration (config_path : Optional [ str ] , backup : bool ):
556+ def _init_claude_integration (config_path : str | None , backup : bool ):
558557 """Initialize Claude Desktop integration."""
559558 console .print ("\n [bold blue]🔧 Setting up Claude Desktop Integration[/bold blue]\n " )
560-
559+
561560 # Determine config path
562561 if not config_path :
563562 # Default Claude Desktop config locations
564563 import platform
565564 system = platform .system ()
566-
565+
567566 if system == "Darwin" : # macOS
568567 default_path = Path .home () / "Library" / "Application Support" / "Claude" / "claude_desktop_config.json"
569568 elif system == "Windows" :
570569 default_path = Path .home () / "AppData" / "Roaming" / "Claude" / "claude_desktop_config.json"
571570 else : # Linux
572571 default_path = Path .home () / ".config" / "claude" / "claude_desktop_config.json"
573-
572+
574573 config_path = default_path
575574 else :
576575 config_path = Path (config_path )
577-
576+
578577 logger .info ("Config path: %s" , config_path )
579-
578+
580579 # Check if config exists
581580 if not config_path .exists ():
582581 logger .warning ("Config file not found at %s" , config_path )
@@ -590,15 +589,15 @@ def _init_claude_integration(config_path: Optional[str], backup: bool):
590589 import shutil
591590 shutil .copy (config_path , backup_path )
592591 logger .debug ("Backed up existing config to %s" , backup_path )
593-
592+
594593 # Load existing config
595594 with open (config_path ) as f :
596595 config = json .load (f )
597-
596+
598597 # Ensure mcpServers exists
599598 if "mcpServers" not in config :
600599 config ["mcpServers" ] = {}
601-
600+
602601 # Add example AgentMesh proxy configuration
603602 example_server = {
604603 "filesystem-protected" : {
@@ -613,44 +612,44 @@ def _init_claude_integration(config_path: Optional[str], backup: bool):
613612 "env" : {},
614613 }
615614 }
616-
615+
617616 # Check if already configured
618617 has_agentmesh = any (
619618 "agentmesh" in str (server .get ("command" , "" ))
620619 for server in config ["mcpServers" ].values ()
621620 )
622-
621+
623622 if not has_agentmesh :
624623 config ["mcpServers" ].update (example_server )
625624 console .print ("\n [green]✓ Added AgentMesh-protected filesystem server example[/green]" )
626625 else :
627626 logger .warning ("AgentMesh proxy already configured" )
628-
627+
629628 # Save updated config
630629 with open (config_path , "w" ) as f :
631630 json .dump (config , f , indent = 2 )
632-
631+
633632 console .print (f"\n [green]✓ Updated { config_path } [/green]" )
634-
633+
635634 # Show instructions
636635 console .print ()
637636 console .print (Panel (
638- """[bold]Next Steps:[/bold]
637+ f """[bold]Next Steps:[/bold]
639638
6406391. Restart Claude Desktop
6416402. AgentMesh will now intercept all tool calls to the protected server
6426413. View logs in the terminal where Claude Desktop was launched
643642
644643[bold]Customization:[/bold]
645- Edit {path } to:
644+ Edit { config_path } to:
646645- Add more protected servers
647646- Change policy level (--policy strict|moderate|permissive)
648647- Disable verification footers (--no-footer)
649648
650649[bold]Example Usage:[/bold]
651650In Claude Desktop, try: "Read the contents of my home directory"
652651AgentMesh will enforce policies and add trust verification to outputs.
653- """ . format ( path = config_path ) ,
652+ """ ,
654653 title = "🎉 Claude Desktop Integration Ready" ,
655654 border_style = "green" ,
656655 ))
0 commit comments