Files
bzzz/internal/hap/terminal.go
anthonyrawlins be761cfe20 Enhance deployment system with retry functionality and improved UX
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>
2025-08-31 10:23:27 +10:00

322 lines
9.3 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}