package plugin import ( "fmt" "sync" "go.uber.org/zap" ) var ( registry []Plugin mu sync.RWMutex ) // Register adds a plugin to the global registry. // Typically called in init() or during application bootstrap. func Register(p Plugin) { mu.Lock() defer mu.Unlock() registry = append(registry, p) } // All returns a copy of all registered plugins. func All() []Plugin { mu.RLock() defer mu.RUnlock() out := make([]Plugin, len(registry)) copy(out, registry) return out } // InitAll initializes all registered plugins in order. // Each plugin's permissions are registered in the sandbox, and Init() is // wrapped with panic recovery so one plugin's failure doesn't crash the process. func InitAll(log *zap.Logger, sandbox *Sandbox) error { for _, p := range All() { meta := p.Metadata() perms := p.Permissions() sandbox.Register(meta.Name, perms) log.Info("initializing plugin", zap.String("name", meta.Name), zap.String("version", meta.Version), ) if err := sandbox.SafeInit(p); err != nil { return fmt.Errorf("plugin %s init failed: %w", meta.Name, err) } } return nil } // Reset clears the registry. Used in tests only. func Reset() { mu.Lock() defer mu.Unlock() registry = nil }