 b207f32d9e
			
		
	
	b207f32d9e
	
	
	
		
			
			- Add complete UCXL address parser with BNF grammar validation - Implement temporal navigation system with bounds checking - Create UCXI HTTP server with REST-like operations - Add comprehensive test suite with 87 passing tests - Integrate with existing BZZZ architecture (opt-in via config) - Support semantic addressing with wildcards and version control Core Features: - UCXL address format: ucxl://agent:role@project:task/temporal/path - Temporal segments: *^, ~~N, ^^N, *~, *~N with navigation logic - UCXI endpoints: GET/PUT/POST/DELETE/ANNOUNCE operations - Production-ready with error handling and graceful shutdown 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			326 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package protocol
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"net/url"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // BzzzURI represents a parsed bzzz:// URI with semantic addressing
 | |
| // Grammar: bzzz://[agent]:[role]@[project]:[task]/[path][?query][#fragment]
 | |
| type BzzzURI struct {
 | |
| 	// Core addressing components
 | |
| 	Agent   string // Agent identifier (e.g., "claude", "any", "*")
 | |
| 	Role    string // Agent role (e.g., "frontend", "backend", "architect")
 | |
| 	Project string // Project context (e.g., "chorus", "bzzz")
 | |
| 	Task    string // Task identifier (e.g., "implement", "review", "test", "*")
 | |
| 	
 | |
| 	// Resource path
 | |
| 	Path string // Resource path (e.g., "/src/main.go", "/docs/api.md")
 | |
| 	
 | |
| 	// Standard URI components
 | |
| 	Query    string // Query parameters
 | |
| 	Fragment string // Fragment identifier
 | |
| 	
 | |
| 	// Original raw URI string
 | |
| 	Raw string
 | |
| }
 | |
| 
 | |
| // URI grammar constants
 | |
| const (
 | |
| 	BzzzScheme = "bzzz"
 | |
| 	
 | |
| 	// Special identifiers
 | |
| 	AnyAgent   = "any"
 | |
| 	AnyRole    = "any"
 | |
| 	AnyProject = "any"
 | |
| 	AnyTask    = "any"
 | |
| 	Wildcard   = "*"
 | |
| )
 | |
| 
 | |
| // Validation patterns
 | |
| var (
 | |
| 	// Component validation patterns
 | |
| 	agentPattern   = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^\*$|^any$`)
 | |
| 	rolePattern    = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^\*$|^any$`)
 | |
| 	projectPattern = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^\*$|^any$`)
 | |
| 	taskPattern    = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$|^\*$|^any$`)
 | |
| 	pathPattern    = regexp.MustCompile(`^/[a-zA-Z0-9\-_/\.]*$|^$`)
 | |
| 	
 | |
| 	// Full URI pattern for validation
 | |
| 	bzzzURIPattern = regexp.MustCompile(`^bzzz://([a-zA-Z0-9\-_*]|any):([a-zA-Z0-9\-_*]|any)@([a-zA-Z0-9\-_*]|any):([a-zA-Z0-9\-_*]|any)(/[a-zA-Z0-9\-_/\.]*)?(\?[^#]*)?(\#.*)?$`)
 | |
| )
 | |
| 
 | |
| // ParseBzzzURI parses a bzzz:// URI string into a BzzzURI struct
 | |
| func ParseBzzzURI(uri string) (*BzzzURI, error) {
 | |
| 	if uri == "" {
 | |
| 		return nil, fmt.Errorf("empty URI")
 | |
| 	}
 | |
| 	
 | |
| 	// Basic scheme validation
 | |
| 	if !strings.HasPrefix(uri, BzzzScheme+"://") {
 | |
| 		return nil, fmt.Errorf("invalid scheme: expected '%s'", BzzzScheme)
 | |
| 	}
 | |
| 	
 | |
| 	// Use Go's standard URL parser for basic parsing
 | |
| 	parsedURL, err := url.Parse(uri)
 | |
| 	if err != nil {
 | |
| 		return nil, fmt.Errorf("failed to parse URI: %w", err)
 | |
| 	}
 | |
| 	
 | |
| 	if parsedURL.Scheme != BzzzScheme {
 | |
| 		return nil, fmt.Errorf("invalid scheme: expected '%s', got '%s'", BzzzScheme, parsedURL.Scheme)
 | |
| 	}
 | |
| 	
 | |
| 	// Parse the authority part (user:pass@host:port becomes agent:role@project:task)
 | |
| 	userInfo := parsedURL.User
 | |
| 	if userInfo == nil {
 | |
| 		return nil, fmt.Errorf("missing agent:role information")
 | |
| 	}
 | |
| 	
 | |
| 	username := userInfo.Username()
 | |
| 	password, hasPassword := userInfo.Password()
 | |
| 	if !hasPassword {
 | |
| 		return nil, fmt.Errorf("missing role information")
 | |
| 	}
 | |
| 	
 | |
| 	agent := username
 | |
| 	role := password
 | |
| 	
 | |
| 	// Parse host:port as project:task
 | |
| 	hostPort := parsedURL.Host
 | |
| 	if hostPort == "" {
 | |
| 		return nil, fmt.Errorf("missing project:task information")
 | |
| 	}
 | |
| 	
 | |
| 	// Split host:port to get project:task
 | |
| 	parts := strings.Split(hostPort, ":")
 | |
| 	if len(parts) != 2 {
 | |
| 		return nil, fmt.Errorf("invalid project:task format: expected 'project:task'")
 | |
| 	}
 | |
| 	
 | |
| 	project := parts[0]
 | |
| 	task := parts[1]
 | |
| 	
 | |
| 	// Create BzzzURI instance
 | |
| 	bzzzURI := &BzzzURI{
 | |
| 		Agent:    agent,
 | |
| 		Role:     role,
 | |
| 		Project:  project,
 | |
| 		Task:     task,
 | |
| 		Path:     parsedURL.Path,
 | |
| 		Query:    parsedURL.RawQuery,
 | |
| 		Fragment: parsedURL.Fragment,
 | |
| 		Raw:      uri,
 | |
| 	}
 | |
| 	
 | |
| 	// Validate components
 | |
| 	if err := bzzzURI.Validate(); err != nil {
 | |
| 		return nil, fmt.Errorf("validation failed: %w", err)
 | |
| 	}
 | |
| 	
 | |
| 	return bzzzURI, nil
 | |
| }
 | |
| 
 | |
| // Validate validates all components of the BzzzURI
 | |
| func (u *BzzzURI) Validate() error {
 | |
| 	// Validate agent
 | |
| 	if u.Agent == "" {
 | |
| 		return fmt.Errorf("agent cannot be empty")
 | |
| 	}
 | |
| 	if !agentPattern.MatchString(u.Agent) {
 | |
| 		return fmt.Errorf("invalid agent format: '%s'", u.Agent)
 | |
| 	}
 | |
| 	
 | |
| 	// Validate role
 | |
| 	if u.Role == "" {
 | |
| 		return fmt.Errorf("role cannot be empty")
 | |
| 	}
 | |
| 	if !rolePattern.MatchString(u.Role) {
 | |
| 		return fmt.Errorf("invalid role format: '%s'", u.Role)
 | |
| 	}
 | |
| 	
 | |
| 	// Validate project
 | |
| 	if u.Project == "" {
 | |
| 		return fmt.Errorf("project cannot be empty")
 | |
| 	}
 | |
| 	if !projectPattern.MatchString(u.Project) {
 | |
| 		return fmt.Errorf("invalid project format: '%s'", u.Project)
 | |
| 	}
 | |
| 	
 | |
| 	// Validate task
 | |
| 	if u.Task == "" {
 | |
| 		return fmt.Errorf("task cannot be empty")
 | |
| 	}
 | |
| 	if !taskPattern.MatchString(u.Task) {
 | |
| 		return fmt.Errorf("invalid task format: '%s'", u.Task)
 | |
| 	}
 | |
| 	
 | |
| 	// Validate path (optional)
 | |
| 	if u.Path != "" && !pathPattern.MatchString(u.Path) {
 | |
| 		return fmt.Errorf("invalid path format: '%s'", u.Path)
 | |
| 	}
 | |
| 	
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // String returns the canonical string representation of the BzzzURI
 | |
| func (u *BzzzURI) String() string {
 | |
| 	uri := fmt.Sprintf("%s://%s:%s@%s:%s", BzzzScheme, u.Agent, u.Role, u.Project, u.Task)
 | |
| 	
 | |
| 	if u.Path != "" {
 | |
| 		uri += u.Path
 | |
| 	}
 | |
| 	
 | |
| 	if u.Query != "" {
 | |
| 		uri += "?" + u.Query
 | |
| 	}
 | |
| 	
 | |
| 	if u.Fragment != "" {
 | |
| 		uri += "#" + u.Fragment
 | |
| 	}
 | |
| 	
 | |
| 	return uri
 | |
| }
 | |
| 
 | |
| // Normalize normalizes the URI components for consistent addressing
 | |
| func (u *BzzzURI) Normalize() {
 | |
| 	// Convert empty wildcards to standard wildcard
 | |
| 	if u.Agent == "" {
 | |
| 		u.Agent = Wildcard
 | |
| 	}
 | |
| 	if u.Role == "" {
 | |
| 		u.Role = Wildcard
 | |
| 	}
 | |
| 	if u.Project == "" {
 | |
| 		u.Project = Wildcard
 | |
| 	}
 | |
| 	if u.Task == "" {
 | |
| 		u.Task = Wildcard
 | |
| 	}
 | |
| 	
 | |
| 	// Normalize to lowercase for consistency
 | |
| 	u.Agent = strings.ToLower(u.Agent)
 | |
| 	u.Role = strings.ToLower(u.Role)
 | |
| 	u.Project = strings.ToLower(u.Project)
 | |
| 	u.Task = strings.ToLower(u.Task)
 | |
| 	
 | |
| 	// Clean path
 | |
| 	if u.Path != "" && !strings.HasPrefix(u.Path, "/") {
 | |
| 		u.Path = "/" + u.Path
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // IsWildcard checks if a component is a wildcard or "any"
 | |
| func IsWildcard(component string) bool {
 | |
| 	return component == Wildcard || component == AnyAgent || component == AnyRole || 
 | |
| 		   component == AnyProject || component == AnyTask
 | |
| }
 | |
| 
 | |
| // Matches checks if this URI matches another URI (with wildcard support)
 | |
| func (u *BzzzURI) Matches(other *BzzzURI) bool {
 | |
| 	if other == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	
 | |
| 	// Check each component with wildcard support
 | |
| 	if !componentMatches(u.Agent, other.Agent) {
 | |
| 		return false
 | |
| 	}
 | |
| 	if !componentMatches(u.Role, other.Role) {
 | |
| 		return false
 | |
| 	}
 | |
| 	if !componentMatches(u.Project, other.Project) {
 | |
| 		return false
 | |
| 	}
 | |
| 	if !componentMatches(u.Task, other.Task) {
 | |
| 		return false
 | |
| 	}
 | |
| 	
 | |
| 	// Path matching (exact or wildcard)
 | |
| 	if u.Path != "" && other.Path != "" && u.Path != other.Path {
 | |
| 		return false
 | |
| 	}
 | |
| 	
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // componentMatches checks if two components match (with wildcard support)
 | |
| func componentMatches(a, b string) bool {
 | |
| 	// Exact match
 | |
| 	if a == b {
 | |
| 		return true
 | |
| 	}
 | |
| 	
 | |
| 	// Wildcard matching
 | |
| 	if IsWildcard(a) || IsWildcard(b) {
 | |
| 		return true
 | |
| 	}
 | |
| 	
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // GetSelectorPriority returns a priority score for URI matching (higher = more specific)
 | |
| func (u *BzzzURI) GetSelectorPriority() int {
 | |
| 	priority := 0
 | |
| 	
 | |
| 	// More specific components get higher priority
 | |
| 	if !IsWildcard(u.Agent) {
 | |
| 		priority += 8
 | |
| 	}
 | |
| 	if !IsWildcard(u.Role) {
 | |
| 		priority += 4
 | |
| 	}
 | |
| 	if !IsWildcard(u.Project) {
 | |
| 		priority += 2
 | |
| 	}
 | |
| 	if !IsWildcard(u.Task) {
 | |
| 		priority += 1
 | |
| 	}
 | |
| 	
 | |
| 	// Path specificity adds priority
 | |
| 	if u.Path != "" && u.Path != "/" {
 | |
| 		priority += 1
 | |
| 	}
 | |
| 	
 | |
| 	return priority
 | |
| }
 | |
| 
 | |
| // ToAddress returns a simplified address representation for P2P routing
 | |
| func (u *BzzzURI) ToAddress() string {
 | |
| 	return fmt.Sprintf("%s:%s@%s:%s", u.Agent, u.Role, u.Project, u.Task)
 | |
| }
 | |
| 
 | |
| // ValidateBzzzURIString validates a bzzz:// URI string without parsing
 | |
| func ValidateBzzzURIString(uri string) error {
 | |
| 	if uri == "" {
 | |
| 		return fmt.Errorf("empty URI")
 | |
| 	}
 | |
| 	
 | |
| 	if !bzzzURIPattern.MatchString(uri) {
 | |
| 		return fmt.Errorf("invalid bzzz:// URI format")
 | |
| 	}
 | |
| 	
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // NewBzzzURI creates a new BzzzURI with the given components
 | |
| func NewBzzzURI(agent, role, project, task, path string) *BzzzURI {
 | |
| 	uri := &BzzzURI{
 | |
| 		Agent:   agent,
 | |
| 		Role:    role,
 | |
| 		Project: project,
 | |
| 		Task:    task,
 | |
| 		Path:    path,
 | |
| 	}
 | |
| 	uri.Normalize()
 | |
| 	return uri
 | |
| }
 | |
| 
 | |
| // ParseAddress parses a simplified address format (agent:role@project:task)
 | |
| func ParseAddress(addr string) (*BzzzURI, error) {
 | |
| 	// Convert simplified address to full URI
 | |
| 	fullURI := BzzzScheme + "://" + addr
 | |
| 	return ParseBzzzURI(fullURI)
 | |
| } |