webui

package
v1.11.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 22, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package webui – media_handlers.go provides HTTP handlers for media upload/download.

Package webui – security_handlers.go implements the security dashboard API endpoints: audit log, tool guard config, vault status, and API keys.

Package webui implements the DevClaw web dashboard. Serves a React SPA (embedded via embed.FS) with a JSON API backend. Chat streaming uses Server-Sent Events (SSE) for real-time token delivery.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AssistantAPI

type AssistantAPI interface {
	// GetConfig returns the current config as a map.
	GetConfigMap() map[string]any

	// UpdateConfigMap updates config fields and persists to disk.
	UpdateConfigMap(updates map[string]any) error

	// ListSessions returns active session metadata.
	ListSessions() []SessionInfo

	// GetSessionMessages returns messages for a session.
	GetSessionMessages(sessionID string) []MessageInfo

	// GetUsageGlobal returns global token usage stats.
	GetUsageGlobal() UsageInfo

	// GetChannelHealth returns health of all channels.
	GetChannelHealth() []ChannelHealthInfo

	// GetSchedulerJobs returns all scheduler jobs.
	GetSchedulerJobs() []JobInfo

	// ListSkills returns available skills.
	ListSkills() []SkillInfo

	// ToggleSkill enables or disables a skill by name.
	ToggleSkill(name string, enabled bool) error

	// SendChatMessage sends a message and blocks until the full response is ready.
	// Used as fallback when streaming is not available.
	SendChatMessage(sessionID, content string) (string, error)

	// StartChatStream starts an agent run with streaming.
	// Returns a RunHandle with an event channel and cancel function.
	// The caller is responsible for reading from Events until it's closed.
	StartChatStream(ctx context.Context, sessionID, content string) (*RunHandle, error)

	// AbortRun cancels an active agent run by session ID.
	AbortRun(sessionID string) bool

	// DeleteSession removes a session.
	DeleteSession(sessionID string) error

	// Security
	GetAuditLog(limit int) []AuditEntry
	GetAuditCount() int
	GetToolGuardStatus() ToolGuardStatus
	UpdateToolGuard(update ToolGuardStatus) error
	GetVaultStatus() VaultStatus
	GetSecurityStatus() SecurityStatus

	// Domain & Network
	GetDomainConfig() DomainConfigInfo
	UpdateDomainConfig(update DomainConfigUpdate) error

	// Webhooks
	ListWebhooks() []WebhookInfo
	CreateWebhook(url string, events []string) (WebhookInfo, error)
	DeleteWebhook(id string) error
	ToggleWebhook(id string, active bool) error
	GetValidWebhookEvents() []string

	// Hooks (lifecycle)
	ListHooks() []HookInfo
	ToggleHook(name string, enabled bool) error
	UnregisterHook(name string) error
	GetHookEvents() []HookEventInfo

	// MCP Servers
	ListMCPServers() []MCPServerInfo
	CreateMCPServer(name, command string, args []string, env map[string]string) error
	UpdateMCPServer(name string, enabled bool) error
	DeleteMCPServer(name string) error
	StartMCPServer(name string) error
	StopMCPServer(name string) error

	// Database
	GetDatabaseStatus() DatabaseStatusInfo
}

AssistantAPI defines the interface the web UI uses to access assistant state. This avoids a direct dependency on the copilot package.

type AssistantAdapter

type AssistantAdapter struct {
	GetConfigMapFn       func() map[string]any
	UpdateConfigMapFn    func(updates map[string]any) error
	ListSessionsFn       func() []SessionInfo
	GetSessionMessagesFn func(sessionID string) []MessageInfo
	GetUsageGlobalFn     func() UsageInfo
	GetChannelHealthFn   func() []ChannelHealthInfo
	GetSchedulerJobsFn   func() []JobInfo
	ListSkillsFn         func() []SkillInfo
	ToggleSkillFn        func(name string, enabled bool) error
	SendChatMessageFn    func(sessionID, content string) (string, error)
	StartChatStreamFn    func(ctx context.Context, sessionID, content string) (*RunHandle, error)
	AbortRunFn           func(sessionID string) bool
	DeleteSessionFn      func(sessionID string) error

	// WhatsApp QR support
	GetWhatsAppStatusFn   func() WhatsAppStatus
	SubscribeWhatsAppQRFn func() (chan WhatsAppQREvent, func())
	RequestWhatsAppQRFn   func() error

	// Security: Audit Log
	GetAuditLogFn   func(limit int) []AuditEntry
	GetAuditCountFn func() int

	// Security: Tool Guard
	GetToolGuardStatusFn func() ToolGuardStatus
	UpdateToolGuardFn    func(update ToolGuardStatus) error

	// Security: Vault (read-only, no values)
	GetVaultStatusFn func() VaultStatus

	// Security: Overview
	GetSecurityStatusFn func() SecurityStatus

	// Domain & Network
	GetDomainConfigFn    func() DomainConfigInfo
	UpdateDomainConfigFn func(update DomainConfigUpdate) error

	// Webhooks
	ListWebhooksFn          func() []WebhookInfo
	CreateWebhookFn         func(url string, events []string) (WebhookInfo, error)
	DeleteWebhookFn         func(id string) error
	ToggleWebhookFn         func(id string, active bool) error
	GetValidWebhookEventsFn func() []string

	// Hooks (lifecycle)
	ListHooksFn      func() []HookInfo
	ToggleHookFn     func(name string, enabled bool) error
	UnregisterHookFn func(name string) error
	GetHookEventsFn  func() []HookEventInfo

	// MCP Servers
	ListMCPServersFn  func() []MCPServerInfo
	CreateMCPServerFn func(name, command string, args []string, env map[string]string) error
	UpdateMCPServerFn func(name string, enabled bool) error
	DeleteMCPServerFn func(name string) error
	StartMCPServerFn  func(name string) error
	StopMCPServerFn   func(name string) error

	// Database
	GetDatabaseStatusFn func() DatabaseStatusInfo
}

AssistantAdapter wraps a generic set of callbacks to satisfy the AssistantAPI interface. This avoids a direct import cycle between copilot and webui.

func (*AssistantAdapter) AbortRun

func (a *AssistantAdapter) AbortRun(sessionID string) bool

func (*AssistantAdapter) CreateMCPServer added in v1.8.0

func (a *AssistantAdapter) CreateMCPServer(name, command string, args []string, env map[string]string) error

func (*AssistantAdapter) CreateWebhook

func (a *AssistantAdapter) CreateWebhook(url string, events []string) (WebhookInfo, error)

func (*AssistantAdapter) DeleteMCPServer added in v1.8.0

func (a *AssistantAdapter) DeleteMCPServer(name string) error

func (*AssistantAdapter) DeleteSession

func (a *AssistantAdapter) DeleteSession(sessionID string) error

func (*AssistantAdapter) DeleteWebhook

func (a *AssistantAdapter) DeleteWebhook(id string) error

func (*AssistantAdapter) GetAuditCount

func (a *AssistantAdapter) GetAuditCount() int

func (*AssistantAdapter) GetAuditLog

func (a *AssistantAdapter) GetAuditLog(limit int) []AuditEntry

func (*AssistantAdapter) GetChannelHealth

func (a *AssistantAdapter) GetChannelHealth() []ChannelHealthInfo

func (*AssistantAdapter) GetConfigMap

func (a *AssistantAdapter) GetConfigMap() map[string]any

func (*AssistantAdapter) GetDatabaseStatus added in v1.8.0

func (a *AssistantAdapter) GetDatabaseStatus() DatabaseStatusInfo

func (*AssistantAdapter) GetDomainConfig

func (a *AssistantAdapter) GetDomainConfig() DomainConfigInfo

func (*AssistantAdapter) GetHookEvents

func (a *AssistantAdapter) GetHookEvents() []HookEventInfo

func (*AssistantAdapter) GetSchedulerJobs

func (a *AssistantAdapter) GetSchedulerJobs() []JobInfo

func (*AssistantAdapter) GetSecurityStatus

func (a *AssistantAdapter) GetSecurityStatus() SecurityStatus

func (*AssistantAdapter) GetSessionMessages

func (a *AssistantAdapter) GetSessionMessages(sessionID string) []MessageInfo

func (*AssistantAdapter) GetToolGuardStatus

func (a *AssistantAdapter) GetToolGuardStatus() ToolGuardStatus

func (*AssistantAdapter) GetUsageGlobal

func (a *AssistantAdapter) GetUsageGlobal() UsageInfo

func (*AssistantAdapter) GetValidWebhookEvents

func (a *AssistantAdapter) GetValidWebhookEvents() []string

func (*AssistantAdapter) GetVaultStatus

func (a *AssistantAdapter) GetVaultStatus() VaultStatus

func (*AssistantAdapter) ListHooks

func (a *AssistantAdapter) ListHooks() []HookInfo

func (*AssistantAdapter) ListMCPServers added in v1.8.0

func (a *AssistantAdapter) ListMCPServers() []MCPServerInfo

func (*AssistantAdapter) ListSessions

func (a *AssistantAdapter) ListSessions() []SessionInfo

func (*AssistantAdapter) ListSkills

func (a *AssistantAdapter) ListSkills() []SkillInfo

func (*AssistantAdapter) ListWebhooks

func (a *AssistantAdapter) ListWebhooks() []WebhookInfo

func (*AssistantAdapter) SendChatMessage

func (a *AssistantAdapter) SendChatMessage(sessionID, content string) (string, error)

func (*AssistantAdapter) StartChatStream

func (a *AssistantAdapter) StartChatStream(ctx context.Context, sessionID, content string) (*RunHandle, error)

func (*AssistantAdapter) StartMCPServer added in v1.8.0

func (a *AssistantAdapter) StartMCPServer(name string) error

func (*AssistantAdapter) StopMCPServer added in v1.8.0

func (a *AssistantAdapter) StopMCPServer(name string) error

func (*AssistantAdapter) ToggleHook

func (a *AssistantAdapter) ToggleHook(name string, enabled bool) error

func (*AssistantAdapter) ToggleSkill

func (a *AssistantAdapter) ToggleSkill(name string, enabled bool) error

func (*AssistantAdapter) ToggleWebhook

func (a *AssistantAdapter) ToggleWebhook(id string, active bool) error

func (*AssistantAdapter) UnregisterHook

func (a *AssistantAdapter) UnregisterHook(name string) error

func (*AssistantAdapter) UpdateConfigMap

func (a *AssistantAdapter) UpdateConfigMap(updates map[string]any) error

func (*AssistantAdapter) UpdateDomainConfig

func (a *AssistantAdapter) UpdateDomainConfig(update DomainConfigUpdate) error

func (*AssistantAdapter) UpdateMCPServer added in v1.8.0

func (a *AssistantAdapter) UpdateMCPServer(name string, enabled bool) error

func (*AssistantAdapter) UpdateToolGuard

func (a *AssistantAdapter) UpdateToolGuard(update ToolGuardStatus) error

type AuditEntry

type AuditEntry struct {
	ID            int64  `json:"id"`
	Tool          string `json:"tool"`
	Caller        string `json:"caller"`
	Level         string `json:"level"`
	Allowed       bool   `json:"allowed"`
	ArgsSummary   string `json:"args_summary"`
	ResultSummary string `json:"result_summary"`
	CreatedAt     string `json:"created_at"`
}

AuditEntry represents a single audit log record for the UI.

type ChannelHealthInfo

type ChannelHealthInfo struct {
	Name       string    `json:"name"`
	Connected  bool      `json:"connected"`
	ErrorCount int       `json:"error_count"`
	LastMsgAt  time.Time `json:"last_msg_at"`
}

ChannelHealthInfo contains channel health for display.

type Config

type Config struct {
	// Enabled turns the web UI on/off.
	Enabled bool `yaml:"enabled"`

	// Address is the listen address (default: ":8090").
	Address string `yaml:"address"`

	// AuthToken is the Bearer token for authentication (empty = no auth).
	AuthToken string `yaml:"auth_token"`
}

Config holds web UI configuration.

type DatabaseStatusInfo added in v1.8.0

type DatabaseStatusInfo struct {
	Name         string `json:"name"`
	Healthy      bool   `json:"healthy"`
	Latency      int64  `json:"latency"` // ms
	Version      string `json:"version"`
	OpenConns    int    `json:"open_connections"`
	InUse        int    `json:"in_use"`
	Idle         int    `json:"idle"`
	WaitCount    int    `json:"wait_count"`
	WaitDuration int64  `json:"wait_duration"` // ms
	MaxOpenConns int    `json:"max_open_conns"`
	Error        string `json:"error,omitempty"`
}

DatabaseStatusInfo contains database health status for the UI.

type DomainConfigInfo

type DomainConfigInfo struct {
	// WebUI settings
	WebuiAddress   string `json:"webui_address"`
	WebuiAuthToken bool   `json:"webui_auth_configured"` // never expose the actual token

	// Gateway API settings
	GatewayEnabled   bool     `json:"gateway_enabled"`
	GatewayAddress   string   `json:"gateway_address"`
	GatewayAuthToken bool     `json:"gateway_auth_configured"`
	CORSOrigins      []string `json:"cors_origins"`

	// Tailscale settings
	TailscaleEnabled  bool   `json:"tailscale_enabled"`
	TailscaleServe    bool   `json:"tailscale_serve"`
	TailscaleFunnel   bool   `json:"tailscale_funnel"`
	TailscalePort     int    `json:"tailscale_port"`
	TailscaleHostname string `json:"tailscale_hostname"`
	TailscaleURL      string `json:"tailscale_url"` // resolved URL if active

	// Computed URLs
	WebuiURL   string `json:"webui_url"`
	GatewayURL string `json:"gateway_url"`
	PublicURL  string `json:"public_url"` // tailscale funnel URL if active
}

DomainConfigInfo contains domain/network configuration for the UI.

type DomainConfigUpdate

type DomainConfigUpdate struct {
	WebuiAddress     *string  `json:"webui_address,omitempty"`
	WebuiAuthToken   *string  `json:"webui_auth_token,omitempty"`
	GatewayEnabled   *bool    `json:"gateway_enabled,omitempty"`
	GatewayAddress   *string  `json:"gateway_address,omitempty"`
	GatewayAuthToken *string  `json:"gateway_auth_token,omitempty"`
	CORSOrigins      []string `json:"cors_origins,omitempty"`
	TailscaleEnabled *bool    `json:"tailscale_enabled,omitempty"`
	TailscaleServe   *bool    `json:"tailscale_serve,omitempty"`
	TailscaleFunnel  *bool    `json:"tailscale_funnel,omitempty"`
	TailscalePort    *int     `json:"tailscale_port,omitempty"`
}

DomainConfigUpdate contains the mutable domain/network fields from the UI.

type HookEventInfo

type HookEventInfo struct {
	Event       string   `json:"event"`
	Description string   `json:"description"`
	Hooks       []string `json:"hooks"` // names of hooks subscribed to this event
}

HookEventInfo describes a supported hook event.

type HookInfo

type HookInfo struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	Source      string   `json:"source"`
	Events      []string `json:"events"`
	Priority    int      `json:"priority"`
	Enabled     bool     `json:"enabled"`
}

HookInfo contains lifecycle hook metadata for the UI.

type JobInfo

type JobInfo struct {
	ID        string    `json:"id"`
	Schedule  string    `json:"schedule"`
	Type      string    `json:"type"`
	Command   string    `json:"command"`
	Enabled   bool      `json:"enabled"`
	RunCount  int       `json:"run_count"`
	LastRunAt time.Time `json:"last_run_at"`
	LastError string    `json:"last_error"`
}

JobInfo contains scheduler job info for display.

type MCPServerInfo added in v1.8.0

type MCPServerInfo struct {
	Name    string            `json:"name"`
	Command string            `json:"command"`
	Args    []string          `json:"args"`
	Env     map[string]string `json:"env"`
	Enabled bool              `json:"enabled"`
	Status  string            `json:"status"` // running, stopped, error
	Error   string            `json:"error,omitempty"`
}

MCPServerInfo contains MCP server info for the UI.

type MediaAPI added in v1.8.0

type MediaAPI interface {
	// Upload stores media and returns its ID, type, and URL.
	Upload(r *http.Request, sessionID string) (mediaID string, mediaType string, filename string, size int64, err error)

	// Get retrieves media by ID.
	Get(mediaID string) ([]byte, string, string, error) // data, mimeType, filename, error

	// List returns media matching the filter.
	List(sessionID string, mediaType string, limit int) ([]MediaInfo, error)

	// Delete removes media by ID.
	Delete(mediaID string) error
}

MediaAPI defines the interface for media operations. Implemented by the media service adapter in the copilot package.

type MediaAdapter added in v1.8.0

type MediaAdapter struct {
	UploadFn func(r *http.Request, sessionID string) (mediaID string, mediaType string, filename string, size int64, err error)
	GetFn    func(mediaID string) ([]byte, string, string, error)
	ListFn   func(sessionID string, mediaType string, limit int) ([]MediaInfo, error)
	DeleteFn func(mediaID string) error
}

MediaAdapter wraps a MediaService to implement the MediaAPI interface. This avoids importing the media package directly in webui.

func (*MediaAdapter) Delete added in v1.8.0

func (m *MediaAdapter) Delete(mediaID string) error

Delete implements MediaAPI.Delete.

func (*MediaAdapter) Get added in v1.8.0

func (m *MediaAdapter) Get(mediaID string) ([]byte, string, string, error)

Get implements MediaAPI.Get.

func (*MediaAdapter) List added in v1.8.0

func (m *MediaAdapter) List(sessionID string, mediaType string, limit int) ([]MediaInfo, error)

List implements MediaAPI.List.

func (*MediaAdapter) Upload added in v1.8.0

func (m *MediaAdapter) Upload(r *http.Request, sessionID string) (string, string, string, int64, error)

Upload implements MediaAPI.Upload.

type MediaInfo added in v1.8.0

type MediaInfo struct {
	ID        string `json:"id"`
	Filename  string `json:"filename"`
	Type      string `json:"type"`
	Size      int64  `json:"size"`
	URL       string `json:"url"`
	CreatedAt string `json:"created_at"`
}

MediaInfo contains media metadata for the UI.

type MessageInfo

type MessageInfo struct {
	Role      string    `json:"role"`
	Content   string    `json:"content"`
	Timestamp time.Time `json:"timestamp"`
}

MessageInfo contains a single message for display.

type RunHandle

type RunHandle struct {
	RunID     string
	SessionID string
	Events    chan StreamEvent // Backend pushes events here; handler writes SSE.
	Cancel    context.CancelFunc
}

RunHandle represents an active agent run that can stream events and be aborted.

type SecurityStatus

type SecurityStatus struct {
	GatewayAuthConfigured bool `json:"gateway_auth_configured"`
	WebUIAuthConfigured   bool `json:"webui_auth_configured"`
	ToolGuardEnabled      bool `json:"tool_guard_enabled"`
	VaultExists           bool `json:"vault_exists"`
	VaultUnlocked         bool `json:"vault_unlocked"`
	AuditEntryCount       int  `json:"audit_entry_count"`
}

SecurityStatus is an overview returned at /api/security.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is the web UI HTTP server.

func New

func New(cfg Config, api AssistantAPI, logger *slog.Logger) *Server

New creates a new web UI server.

func (*Server) OnSetupDone

func (s *Server) OnSetupDone(fn func())

OnSetupDone registers a callback invoked when the setup wizard finishes.

func (*Server) OnVaultInit

func (s *Server) OnVaultInit(fn func(password string, secrets map[string]string) error)

OnVaultInit registers a callback to create the encrypted vault during setup.

func (*Server) SetMediaAPI added in v1.8.0

func (s *Server) SetMediaAPI(api MediaAPI)

SetMediaAPI sets the media API for file upload/download operations.

func (*Server) SetSetupMode

func (s *Server) SetSetupMode(enabled bool)

SetSetupMode enables setup-only mode (no assistant, only setup + auth endpoints).

func (*Server) Start

func (s *Server) Start(ctx context.Context) error

Start begins serving the web UI.

func (*Server) Stop

func (s *Server) Stop()

Stop gracefully shuts down the web UI server.

type SessionInfo

type SessionInfo struct {
	ID            string    `json:"id"`
	Channel       string    `json:"channel"`
	ChatID        string    `json:"chat_id"`
	MessageCount  int       `json:"message_count"`
	LastMessageAt time.Time `json:"last_message_at"`
	CreatedAt     time.Time `json:"created_at"`
}

SessionInfo contains session metadata for the UI.

type SetupRequest

type SetupRequest struct {
	Name          string          `json:"name"`
	Language      string          `json:"language"`
	Timezone      string          `json:"timezone"`
	Provider      string          `json:"provider"`
	APIKey        string          `json:"apiKey"`
	Model         string          `json:"model"`
	BaseURL       string          `json:"baseUrl"`
	OwnerPhone    string          `json:"ownerPhone"`
	WebuiPassword string          `json:"webuiPassword"`
	VaultPassword string          `json:"vaultPassword"`
	AccessMode    string          `json:"accessMode"`
	Channels      map[string]bool `json:"channels"`
	EnabledSkills []string        `json:"enabledSkills"`
}

SetupRequest contains all data from the setup wizard frontend.

type SkillInfo

type SkillInfo struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Enabled     bool   `json:"enabled"`
	ToolCount   int    `json:"tool_count"`
}

SkillInfo contains skill info for display.

type StreamEvent

type StreamEvent struct {
	Type string `json:"type"` // delta, tool_use, tool_result, done, error
	Data any    `json:"data"`
}

StreamEvent is a typed SSE event sent to the frontend.

type ToolGuardStatus

type ToolGuardStatus struct {
	Enabled             bool              `json:"enabled"`
	AllowDestructive    bool              `json:"allow_destructive"`
	AllowSudo           bool              `json:"allow_sudo"`
	AllowReboot         bool              `json:"allow_reboot"`
	AutoApprove         []string          `json:"auto_approve"`
	RequireConfirmation []string          `json:"require_confirmation"`
	ProtectedPaths      []string          `json:"protected_paths"`
	SSHAllowedHosts     []string          `json:"ssh_allowed_hosts"`
	DangerousCommands   []string          `json:"dangerous_commands"`
	ToolPermissions     map[string]string `json:"tool_permissions"`
}

ToolGuardStatus represents the tool guard configuration for the UI.

type UsageInfo

type UsageInfo struct {
	TotalInputTokens  int64   `json:"total_input_tokens"`
	TotalOutputTokens int64   `json:"total_output_tokens"`
	TotalCost         float64 `json:"total_cost"`
	RequestCount      int64   `json:"request_count"`
}

UsageInfo contains token usage statistics.

type VaultStatus

type VaultStatus struct {
	Exists   bool     `json:"exists"`
	Unlocked bool     `json:"unlocked"`
	Keys     []string `json:"keys"`
}

VaultStatus represents the vault state for the UI (no secret values).

type WebhookInfo

type WebhookInfo struct {
	ID        string    `json:"id"`
	URL       string    `json:"url"`
	Events    []string  `json:"events"`
	Active    bool      `json:"active"`
	CreatedAt time.Time `json:"created_at"`
}

WebhookInfo contains webhook metadata for the UI.

type WhatsAppQREvent

type WhatsAppQREvent struct {
	Type        string `json:"type"` // "code", "success", "timeout", "error", "refresh"
	Code        string `json:"code,omitempty"`
	Message     string `json:"message"`
	ExpiresAt   string `json:"expires_at,omitempty"`   // ISO timestamp
	SecondsLeft int    `json:"seconds_left,omitempty"` // Seconds until QR expires
}

WhatsAppQREvent mirrors whatsapp.QREvent without importing the channel package.

type WhatsAppStatus

type WhatsAppStatus struct {
	Connected         bool   `json:"connected"`
	State             string `json:"state"` // "disconnected", "connecting", "connected", "waiting_qr", etc.
	NeedsQR           bool   `json:"needs_qr"`
	Phone             string `json:"phone,omitempty"`
	Platform          string `json:"platform,omitempty"`
	ErrorCount        int    `json:"error_count"`
	ReconnectAttempts int    `json:"reconnect_attempts"`
	Message           string `json:"message,omitempty"` // Human-readable status message
}

WhatsAppStatus holds the current WhatsApp connection state for the UI.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL