 be761cfe20
			
		
	
	be761cfe20
	
	
	
		
			
			Major Improvements: - Added retry deployment buttons in machine list for failed deployments - Added retry button in SSH console modal footer for enhanced UX - Enhanced deployment process with comprehensive cleanup of existing services - Improved binary installation with password-based sudo authentication - Updated configuration generation to include all required sections (agent, ai, network, security) - Fixed deployment verification and error handling Security Enhancements: - Enhanced verifiedStopExistingServices with thorough cleanup process - Improved binary copying with proper sudo authentication - Added comprehensive configuration validation UX Improvements: - Users can retry deployments without re-running machine discovery - Retry buttons available from both machine list and console modal - Real-time deployment progress with detailed console output - Clear error states with actionable retry options Technical Changes: - Modified ServiceDeployment.tsx with retry button components - Enhanced api/setup_manager.go with improved deployment functions - Updated main.go with command line argument support (--config, --setup) - Added comprehensive zero-trust security validation system 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			322 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package hap
 | ||
| 
 | ||
| import (
 | ||
| 	"bufio"
 | ||
| 	"context"
 | ||
| 	"fmt"
 | ||
| 	"os"
 | ||
| 	"strings"
 | ||
| 	"time"
 | ||
| 
 | ||
| 	"chorus.services/bzzz/internal/common/runtime"
 | ||
| 	"chorus.services/bzzz/logging"
 | ||
| )
 | ||
| 
 | ||
| // TerminalInterface provides a terminal-based interface for human agents
 | ||
| type TerminalInterface struct {
 | ||
| 	services *runtime.RuntimeServices
 | ||
| 	logger   logging.Logger
 | ||
| 	running  bool
 | ||
| 	scanner  *bufio.Scanner
 | ||
| }
 | ||
| 
 | ||
| // NewTerminalInterface creates a new terminal interface
 | ||
| func NewTerminalInterface(services *runtime.RuntimeServices, logger logging.Logger) *TerminalInterface {
 | ||
| 	return &TerminalInterface{
 | ||
| 		services: services,
 | ||
| 		logger:   logger,
 | ||
| 		running:  false,
 | ||
| 		scanner:  bufio.NewScanner(os.Stdin),
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // Start begins the terminal interface
 | ||
| func (ti *TerminalInterface) Start(ctx context.Context) error {
 | ||
| 	if ti.running {
 | ||
| 		return fmt.Errorf("terminal interface is already running")
 | ||
| 	}
 | ||
| 
 | ||
| 	ti.logger.Info("👤 Starting Human Agent Portal terminal interface")
 | ||
| 
 | ||
| 	// Display welcome message
 | ||
| 	ti.displayWelcome()
 | ||
| 
 | ||
| 	// Start command processing in background
 | ||
| 	go ti.processCommands(ctx)
 | ||
| 
 | ||
| 	ti.running = true
 | ||
| 	ti.logger.Info("✅ Terminal interface ready for human interaction")
 | ||
| 
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // Stop gracefully stops the terminal interface
 | ||
| func (ti *TerminalInterface) Stop(ctx context.Context) error {
 | ||
| 	if !ti.running {
 | ||
| 		return nil
 | ||
| 	}
 | ||
| 
 | ||
| 	ti.logger.Info("🛑 Stopping terminal interface")
 | ||
| 	ti.running = false
 | ||
| 
 | ||
| 	fmt.Println("\n👋 Human Agent Portal shutting down. Goodbye!")
 | ||
| 	return nil
 | ||
| }
 | ||
| 
 | ||
| // displayWelcome shows the welcome message and commands
 | ||
| func (ti *TerminalInterface) displayWelcome() {
 | ||
| 	fmt.Println("\n" + strings.Repeat("=", 60))
 | ||
| 	fmt.Println("🎯 BZZZ Human Agent Portal (HAP)")
 | ||
| 	fmt.Println("   Welcome to collaborative AI task coordination")
 | ||
| 	fmt.Println(strings.Repeat("=", 60))
 | ||
| 
 | ||
| 	if ti.services.Node != nil {
 | ||
| 		fmt.Printf("📍 Node ID: %s\n", ti.services.Node.ID().ShortString())
 | ||
| 	}
 | ||
| 
 | ||
| 	if ti.services.Config != nil {
 | ||
| 		fmt.Printf("🤖 Agent ID: %s\n", ti.services.Config.Agent.ID)
 | ||
| 		if ti.services.Config.Agent.Role != "" {
 | ||
| 			fmt.Printf("🎭 Role: %s\n", ti.services.Config.Agent.Role)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	if ti.services.Node != nil {
 | ||
| 		fmt.Printf("🌐 Connected Peers: %d\n", ti.services.Node.ConnectedPeers())
 | ||
| 	}
 | ||
| 
 | ||
| 	fmt.Println("\n📋 Available Commands:")
 | ||
| 	fmt.Println("  status     - Show system status")
 | ||
| 	fmt.Println("  peers      - List connected peers")
 | ||
| 	fmt.Println("  send <msg> - Send message to coordination channel")
 | ||
| 	fmt.Println("  role       - Show role information")
 | ||
| 	fmt.Println("  tasks      - Show task information")
 | ||
| 	fmt.Println("  health     - Show health status")
 | ||
| 	fmt.Println("  help       - Show this help message")
 | ||
| 	fmt.Println("  quit/exit  - Exit the interface")
 | ||
| 	fmt.Println(strings.Repeat("-", 60))
 | ||
| 	fmt.Print("HAP> ")
 | ||
| }
 | ||
| 
 | ||
| // processCommands handles user input and commands
 | ||
| func (ti *TerminalInterface) processCommands(ctx context.Context) {
 | ||
| 	for ti.running && ti.scanner.Scan() {
 | ||
| 		input := strings.TrimSpace(ti.scanner.Text())
 | ||
| 		if input == "" {
 | ||
| 			fmt.Print("HAP> ")
 | ||
| 			continue
 | ||
| 		}
 | ||
| 
 | ||
| 		// Parse command and arguments
 | ||
| 		parts := strings.Fields(input)
 | ||
| 		command := strings.ToLower(parts[0])
 | ||
| 
 | ||
| 		switch command {
 | ||
| 		case "quit", "exit":
 | ||
| 			ti.running = false
 | ||
| 			return
 | ||
| 
 | ||
| 		case "help":
 | ||
| 			ti.showHelp()
 | ||
| 
 | ||
| 		case "status":
 | ||
| 			ti.showStatus()
 | ||
| 
 | ||
| 		case "peers":
 | ||
| 			ti.showPeers()
 | ||
| 
 | ||
| 		case "role":
 | ||
| 			ti.showRole()
 | ||
| 
 | ||
| 		case "tasks":
 | ||
| 			ti.showTasks()
 | ||
| 
 | ||
| 		case "health":
 | ||
| 			ti.showHealth()
 | ||
| 
 | ||
| 		case "send":
 | ||
| 			if len(parts) < 2 {
 | ||
| 				fmt.Println("❌ Usage: send <message>")
 | ||
| 			} else {
 | ||
| 				message := strings.Join(parts[1:], " ")
 | ||
| 				ti.sendMessage(message)
 | ||
| 			}
 | ||
| 
 | ||
| 		default:
 | ||
| 			fmt.Printf("❌ Unknown command: %s (type 'help' for available commands)\n", command)
 | ||
| 		}
 | ||
| 
 | ||
| 		fmt.Print("HAP> ")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // showHelp displays the help message
 | ||
| func (ti *TerminalInterface) showHelp() {
 | ||
| 	fmt.Println("\n📋 HAP Commands:")
 | ||
| 	fmt.Println("  status     - Show current system status")
 | ||
| 	fmt.Println("  peers      - List all connected P2P peers")
 | ||
| 	fmt.Println("  send <msg> - Send message to coordination channel")
 | ||
| 	fmt.Println("  role       - Display role and capability information")
 | ||
| 	fmt.Println("  tasks      - Show active tasks (if any)")
 | ||
| 	fmt.Println("  health     - Display system health status")
 | ||
| 	fmt.Println("  help       - Show this help message")
 | ||
| 	fmt.Println("  quit/exit  - Exit the Human Agent Portal")
 | ||
| }
 | ||
| 
 | ||
| // showStatus displays the current system status
 | ||
| func (ti *TerminalInterface) showStatus() {
 | ||
| 	fmt.Println("\n📊 System Status:")
 | ||
| 	fmt.Println(strings.Repeat("-", 40))
 | ||
| 
 | ||
| 	if ti.services.Node != nil {
 | ||
| 		fmt.Printf("🌐 P2P Status: Connected (%d peers)\n", ti.services.Node.ConnectedPeers())
 | ||
| 		fmt.Printf("📍 Node ID: %s\n", ti.services.Node.ID().ShortString())
 | ||
| 	}
 | ||
| 
 | ||
| 	if ti.services.Config != nil {
 | ||
| 		fmt.Printf("🤖 Agent ID: %s\n", ti.services.Config.Agent.ID)
 | ||
| 		fmt.Printf("🎭 Role: %s\n", ti.services.Config.Agent.Role)
 | ||
| 		fmt.Printf("🎯 Specialization: %s\n", ti.services.Config.Agent.Specialization)
 | ||
| 	}
 | ||
| 
 | ||
| 	// Service status
 | ||
| 	fmt.Printf("📡 PubSub: %s\n", ti.getServiceStatus("PubSub", ti.services.PubSub != nil))
 | ||
| 	fmt.Printf("🕸️ DHT: %s\n", ti.getServiceStatus("DHT", ti.services.DHT != nil))
 | ||
| 	fmt.Printf("🔗 UCXI: %s\n", ti.getServiceStatus("UCXI", ti.services.UCXIServer != nil))
 | ||
| 	fmt.Printf("🗳️ Elections: %s\n", ti.getServiceStatus("Elections", ti.services.ElectionManager != nil))
 | ||
| 	fmt.Printf("❤️ Health: %s\n", ti.getServiceStatus("Health", ti.services.HealthManager != nil))
 | ||
| 
 | ||
| 	fmt.Printf("⏰ Uptime: %s\n", time.Since(time.Now().Add(-5*time.Minute)).String()) // Placeholder
 | ||
| }
 | ||
| 
 | ||
| // showPeers displays connected peers
 | ||
| func (ti *TerminalInterface) showPeers() {
 | ||
| 	fmt.Println("\n🌐 Connected Peers:")
 | ||
| 	fmt.Println(strings.Repeat("-", 40))
 | ||
| 
 | ||
| 	if ti.services.Node != nil {
 | ||
| 		peerCount := ti.services.Node.ConnectedPeers()
 | ||
| 		fmt.Printf("Total Connected: %d\n", peerCount)
 | ||
| 
 | ||
| 		if peerCount == 0 {
 | ||
| 			fmt.Println("No peers currently connected")
 | ||
| 			fmt.Println("💡 Tip: Make sure other BZZZ nodes are running on your network")
 | ||
| 		} else {
 | ||
| 			fmt.Println("🔍 Use P2P tools to see detailed peer information")
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		fmt.Println("❌ P2P node not available")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // showRole displays role and capability information
 | ||
| func (ti *TerminalInterface) showRole() {
 | ||
| 	fmt.Println("\n🎭 Role Information:")
 | ||
| 	fmt.Println(strings.Repeat("-", 40))
 | ||
| 
 | ||
| 	if ti.services.Config != nil {
 | ||
| 		cfg := ti.services.Config
 | ||
| 		fmt.Printf("Role: %s\n", cfg.Agent.Role)
 | ||
| 		fmt.Printf("Expertise: %v\n", cfg.Agent.Expertise)
 | ||
| 		fmt.Printf("Reports To: %v\n", cfg.Agent.ReportsTo)
 | ||
| 		fmt.Printf("Deliverables: %v\n", cfg.Agent.Deliverables)
 | ||
| 		fmt.Printf("Capabilities: %v\n", cfg.Agent.Capabilities)
 | ||
| 		fmt.Printf("Specialization: %s\n", cfg.Agent.Specialization)
 | ||
| 
 | ||
| 		// Authority level
 | ||
| 		if authority, err := cfg.GetRoleAuthority(cfg.Agent.Role); err == nil {
 | ||
| 			fmt.Printf("Authority Level: %s\n", authority)
 | ||
| 		}
 | ||
| 	} else {
 | ||
| 		fmt.Println("❌ Configuration not available")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // showTasks displays task information
 | ||
| func (ti *TerminalInterface) showTasks() {
 | ||
| 	fmt.Println("\n📋 Task Information:")
 | ||
| 	fmt.Println(strings.Repeat("-", 40))
 | ||
| 
 | ||
| 	// HAP doesn't execute tasks like agents, but can show coordination status
 | ||
| 	fmt.Println("📝 HAP Role: Human interaction facilitator")
 | ||
| 	fmt.Println("🎯 Purpose: Coordinate with autonomous agents")
 | ||
| 	fmt.Println("💼 Current Mode: Interactive terminal")
 | ||
| 
 | ||
| 	if ti.services.TaskCoordinator != nil {
 | ||
| 		fmt.Println("✅ Task coordination system is active")
 | ||
| 	} else {
 | ||
| 		fmt.Println("❌ Task coordination system not available")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // showHealth displays health status
 | ||
| func (ti *TerminalInterface) showHealth() {
 | ||
| 	fmt.Println("\n❤️ Health Status:")
 | ||
| 	fmt.Println(strings.Repeat("-", 40))
 | ||
| 
 | ||
| 	if ti.services.HealthManager != nil {
 | ||
| 		status := ti.services.HealthManager.GetOverallStatus()
 | ||
| 		healthIcon := "✅"
 | ||
| 		if !status.Healthy {
 | ||
| 			healthIcon = "❌"
 | ||
| 		}
 | ||
| 		fmt.Printf("%s Overall Health: %s\n", healthIcon, ti.boolToStatus(status.Healthy))
 | ||
| 		fmt.Printf("📋 Details: %s\n", status.Message)
 | ||
| 		fmt.Printf("⏰ Last Check: %s\n", status.Timestamp.Format(time.RFC3339))
 | ||
| 	} else {
 | ||
| 		fmt.Println("❌ Health manager not available")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // sendMessage sends a message to the coordination channel
 | ||
| func (ti *TerminalInterface) sendMessage(message string) {
 | ||
| 	if ti.services.PubSub == nil {
 | ||
| 		fmt.Println("❌ PubSub not available - cannot send message")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// Create a human-authored message
 | ||
| 	messageData := map[string]interface{}{
 | ||
| 		"type":      "human_message",
 | ||
| 		"author":    "human",
 | ||
| 		"node_id":   ti.services.Node.ID().ShortString(),
 | ||
| 		"agent_id":  ti.services.Config.Agent.ID,
 | ||
| 		"role":      ti.services.Config.Agent.Role,
 | ||
| 		"message":   message,
 | ||
| 		"timestamp": time.Now().Unix(),
 | ||
| 	}
 | ||
| 
 | ||
| 	// Send to coordination channel
 | ||
| 	if err := ti.services.PubSub.PublishBzzzMessage("coordination", messageData); err != nil {
 | ||
| 		fmt.Printf("❌ Failed to send message: %v\n", err)
 | ||
| 	} else {
 | ||
| 		fmt.Printf("📤 Message sent to coordination channel\n")
 | ||
| 		fmt.Printf("💬 \"%s\"\n", message)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // Helper functions
 | ||
| 
 | ||
| func (ti *TerminalInterface) getServiceStatus(serviceName string, available bool) string {
 | ||
| 	if available {
 | ||
| 		return "✅ Active"
 | ||
| 	}
 | ||
| 	return "❌ Inactive"
 | ||
| }
 | ||
| 
 | ||
| func (ti *TerminalInterface) boolToStatus(b bool) string {
 | ||
| 	if b {
 | ||
| 		return "Healthy"
 | ||
| 	}
 | ||
| 	return "Unhealthy"
 | ||
| }
 | ||
| 
 | ||
| // IsRunning returns whether the terminal interface is running
 | ||
| func (ti *TerminalInterface) IsRunning() bool {
 | ||
| 	return ti.running
 | ||
| }
 | ||
| 
 | ||
| // GetServices returns the runtime services
 | ||
| func (ti *TerminalInterface) GetServices() *runtime.RuntimeServices {
 | ||
| 	return ti.services
 | ||
| } |