Binder manages mapping of keys to handlers, auto-discovery from struct tags,
before/after hooks, and optional JSON backup.
AddBool overrides the default handler for key with a custom bool→error function.
{
	b.handlers[key] = wrapBool(fn)
}AddInt overrides the default handler for key with a custom int→error function.
{
	b.handlers[key] = wrapInt(fn)
}AddDuration overrides the default handler for key with a custom duration→error function.
{
	b.handlers[key] = wrapDuration(fn)
}AddEnum overrides the default handler for key with a custom enum handler enforcing choices.
{
	b.handlers[key] = wrapEnum(choices, fn)
}AddStrings overrides the default handler for key with a custom []string→error function.
{
	b.handlers[key] = fn
}BeforeHook registers a hook called before setting a field.
{
	b.hooks.addBefore(key, fn)
}AfterHook registers a hook called after setting a field.
{
	b.hooks.addAfter(key, fn)
}Run applies handler for key with args, invoking before and after hooks.
{
	b.hooks.runBefore(key, args)
	h, ok := b.handlers[key]
	if !ok {
		return fmt.Errorf("no handler for key %s", key)
	}
	err := h(args)
	b.hooks.runAfter(key, args)
	return err
}RunAll applies multiple key→args mappings in sequence.
{
	for k, args := range batch {
		if err := b.Run(k, args); err != nil {
			return err
		}
	}
	return nil
}HandlerFunc processes raw args for a field.
func(args []string) error
HookFunc defines a hook signature.
func(key string, args []string)
hooks stores before/after hook functions.
addBefore registers a before-hook for a key.
{
	h.before[key] = append(h.before[key], fn)
}addAfter registers an after-hook for a key.
{
	h.after[key] = append(h.after[key], fn)
}runBefore executes all before-hooks for a key.
{
	for _, fn := range h.before[key] {
		fn(key, args)
	}
}runAfter executes all after-hooks for a key.
{
	for _, fn := range h.after[key] {
		fn(key, args)
	}
}NewBinder creates a Binder for dst and optionally writes a JSON backup to backupDir.
{
	if autobackup {
		if err := os.MkdirAll(backupDir, 0o755); err != nil {
			return nil, err
		}
		backupPath := filepath.Join(backupDir, fmt.Sprintf("backup-%d.json", time.Now().Unix()))
		f, err := os.Create(backupPath)
		if err != nil {
			return nil, err
		}
		defer f.Close()
		if err := json.NewEncoder(f).Encode(dst); err != nil {
			return nil, err
		}
	}
	b := &Binder{
		dst:      dst,
		handlers: make(map[string]HandlerFunc),
		hooks:    newHooks(),
	}
	autoDiscover(b)
	return b, nil
}parseTag splits a tag like "socketX11,bool" or "mode,enum,dev|prod" into tagMeta.
{
	parts := strings.Split(tag, ",")
	meta := tagMeta{Name: parts[0], Type: parts[1]}
	if meta.Type == "enum" && len(parts) > 2 {
		meta.Choices = strings.Split(parts[2], "|")
	}
	return meta
}autoDiscover inspects dst struct tags and registers default handlers.
{
	v := reflect.ValueOf(b.dst).Elem()
	t := v.Type()
	for i := range t.NumField() {
		f := t.Field(i)
		tag := f.Tag.Get("flag")
		if tag == "" {
			continue
		}
		meta := parseTag(tag)
		field := v.Field(i)
		switch meta.Type {
		case "bool":
			b.handlers[meta.Name] = defaultBool(field)
		case "int":
			b.handlers[meta.Name] = defaultInt(field)
		case "duration":
			b.handlers[meta.Name] = defaultDuration(field)
		case "enum":
			b.handlers[meta.Name] = defaultEnum(field, meta.Choices)
		case "strings":
			b.handlers[meta.Name] = defaultStrings(field)
		}
	}
}wrapBool adapts fn to HandlerFunc.
{
	return func(args []string) error {
		v, err := strconv.ParseBool(args[0])
		if err != nil {
			return err
		}
		return fn(v)
	}
}defaultBool returns a HandlerFunc that sets a reflect.Bool field.
{
	return func(args []string) error {
		v, err := strconv.ParseBool(args[0])
		if err != nil {
			return err
		}
		field.SetBool(v)
		return nil
	}
}wrapInt adapts fn to HandlerFunc.
{
	return func(args []string) error {
		v, err := strconv.ParseInt(args[0], 10, 64)
		if err != nil {
			return err
		}
		return fn(v)
	}
}defaultInt returns a HandlerFunc that sets a reflect.Int field.
{
	return func(args []string) error {
		v, err := strconv.ParseInt(args[0], 10, 64)
		if err != nil {
			return err
		}
		field.SetInt(v)
		return nil
	}
}wrapDuration adapts fn to HandlerFunc.
{
	return func(args []string) error {
		d, err := time.ParseDuration(args[0])
		if err != nil {
			return err
		}
		return fn(d)
	}
}defaultDuration returns a HandlerFunc that sets a duration-stored-as-int64 field.
{
	return func(args []string) error {
		d, err := time.ParseDuration(args[0])
		if err != nil {
			return err
		}
		field.SetInt(int64(d))
		return nil
	}
}wrapEnum enforces allowed choices then calls fn.
{
	return func(args []string) error {
		v := args[0]
		for _, c := range choices {
			if v == c {
				return fn(v)
			}
		}
		return fmt.Errorf("invalid value %q, must be one of %v", v, choices)
	}
}defaultEnum returns a HandlerFunc that sets a string field with validation.
{
	return func(args []string) error {
		v := args[0]
		for _, c := range choices {
			if v == c {
				field.SetString(v)
				return nil
			}
		}
		return fmt.Errorf("invalid value %q, must be one of %v", v, choices)
	}
}defaultStrings returns a HandlerFunc that sets a []string field.
{
	return func(args []string) error {
		var parts []string
		if len(args) == 1 {
			parts = strings.Split(args[0], ":")
		} else {
			parts = args
		}
		slice := reflect.MakeSlice(field.Type(), len(parts), len(parts))
		for i, s := range parts {
			slice.Index(i).SetString(s)
		}
		field.Set(slice)
		return nil
	}
}newHooks creates an empty hooks registry.
{
	return &hooks{
		before: make(map[string][]HookFunc),
		after:  make(map[string][]HookFunc),
	}
}import "encoding/json"import "fmt"import "os"import "path/filepath"import "time"import "reflect"import "strings"import "fmt"import "reflect"import "strconv"import "strings"import "time"