Files
synapbus/internal/console/console.go
T
Algis DumbrisandClaude Opus 4.6 2575ce2626 feat: OAuth 2.1 with PKCE, MCP auth, dead letters, channel management, and UX polish
- Add OAuth 2.1 identity provider with PKCE S256 (ory/fosite)
- Add RFC 7591 dynamic client registration for MCP clients
- Add RFC 8414 OAuth metadata discovery endpoint
- Add branded OAuth login/authorize pages with SynapBus design
- Add SYNAPBUS_BASE_URL env var for remote/LAN deployments
- Add OAuth bearer token authentication for MCP connections
- Add dead letter queue with Web UI management page
- Add channel leave, member list, and improved channel management
- Add agent auth middleware for MCP-authenticated requests
- Add console printer for structured server startup output
- Hide human accounts from agent management UI
- Fix SSE through middleware (Flush/Unwrap support)
- Fix graceful shutdown by closing SSE clients before server stop
- Fix localhost/127.0.0.1 redirect URI normalization for OAuth
- Remove agent self-registration MCP tools (manage via Web UI only)
- Update README with OAuth setup guide and MCP client config example

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 12:54:02 +02:00

120 lines
2.8 KiB
Go

// Package console provides pretty terminal output for the SynapBus server.
package console
import (
"fmt"
"io"
"os"
"sync"
)
// ANSI color codes
const (
reset = "\033[0m"
green = "\033[32m"
cyan = "\033[36m"
yellow = "\033[33m"
gray = "\033[90m"
bold = "\033[1m"
red = "\033[31m"
)
// Printer writes pretty-formatted console output.
type Printer struct {
mu sync.Mutex
out io.Writer
}
// New creates a Printer writing to stdout.
func New() *Printer {
return &Printer{out: os.Stdout}
}
// NewWithWriter creates a Printer writing to the given writer (for testing).
func NewWithWriter(w io.Writer) *Printer {
return &Printer{out: w}
}
// Success prints a green checkmark line: ✓ message
func (p *Printer) Success(msg string) {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintf(p.out, "%s✓%s %s\n", green, reset, msg)
}
// Arrow prints a cyan arrow line: → message
func (p *Printer) Arrow(msg string) {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintf(p.out, "%s→%s %s\n", cyan, reset, msg)
}
// Info prints a gray info line.
func (p *Printer) Info(msg string) {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintf(p.out, "%s%s%s\n", gray, msg, reset)
}
// Warn prints a yellow warning line.
func (p *Printer) Warn(msg string) {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintf(p.out, "%s⚠ %s%s\n", yellow, msg, reset)
}
// Error prints a red error line.
func (p *Printer) Error(msg string) {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintf(p.out, "%s✗ %s%s\n", red, msg, reset)
}
// Blank prints an empty line.
func (p *Printer) Blank() {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintln(p.out)
}
// AgentConnected prints a formatted agent connection event.
func (p *Printer) AgentConnected(name, clientName, clientVersion string) {
p.mu.Lock()
defer p.mu.Unlock()
if clientName != "" {
version := ""
if clientVersion != "" {
version = " " + clientVersion
}
fmt.Fprintf(p.out, "%s→%s Agent %s\"%s\"%s connected %s(%s%s)%s\n",
cyan, reset, bold, name, reset, gray, clientName, version, reset)
} else {
fmt.Fprintf(p.out, "%s→%s Agent %s\"%s\"%s connected\n",
cyan, reset, bold, name, reset)
}
}
// AgentDisconnected prints a formatted agent disconnection event.
func (p *Printer) AgentDisconnected(name string) {
p.mu.Lock()
defer p.mu.Unlock()
fmt.Fprintf(p.out, "%s←%s Agent %s\"%s\"%s disconnected\n",
yellow, reset, bold, name, reset)
}
// ClientConnected prints an anonymous client connection (no agent identity).
func (p *Printer) ClientConnected(clientName, clientVersion string) {
p.mu.Lock()
defer p.mu.Unlock()
if clientName != "" {
version := ""
if clientVersion != "" {
version = " " + clientVersion
}
fmt.Fprintf(p.out, "%s→%s Client connected %s(%s%s)%s\n",
cyan, reset, gray, clientName, version, reset)
} else {
fmt.Fprintf(p.out, "%s→%s Client connected\n", cyan, reset)
}
}