Skip to content

Replace string+normalize daemon timeout flags with a custom pflag.Value duration type #286

Description

@peteski22

The daemon timeout and interval flags are registered as strings, normalized and validated late in validateFlags, then re-parsed in buildAPIOptions/buildDaemonOptions. Normalization and validation are split across a per-flag table in validateFlags and each option builder, and durations are stored as string with an invariant (valid, positive duration) the type does not enforce. This shape is what allowed --timeout-mcp-shutdown to be validated but never applied until #284.

A custom pflag.Value duration type would normalize and validate once, at flag-parse time, and let the config carry time.Duration:

type durationSeconds struct{ d time.Duration }

func (v *durationSeconds) Set(s string) error {
	s = strings.TrimSpace(s)
	if _, err := time.ParseDuration(s); err != nil {
		if _, err2 := time.ParseDuration(s + "s"); err2 == nil {
			s += "s" // bare number -> seconds
		}
	}
	d, err := time.ParseDuration(s)
	if err != nil {
		return fmt.Errorf("must be a duration such as 30s or 1m")
	}
	if d <= 0 {
		return fmt.Errorf("must be positive")
	}
	v.d = d
	return nil
}

func (v *durationSeconds) String() string { return v.d.String() }
func (v *durationSeconds) Type() string   { return "duration" }

Registered with Flags().Var(...), this would:

  • Normalize and validate once, when cobra parses the flag, before RunE — invalid input fails immediately with a per-flag error.
  • Store time.Duration in the config struct, so buildAPIOptions/buildDaemonOptions read the value directly with no re-parse and no duplicated error handling.
  • Remove the per-flag validation table, so a new duration flag inherits the behavior by type — eliminating the drift fix(cmd): accept bare seconds, reject negatives, and wire --timeout-mcp-shutdown for daemon timeouts #284 worked around.
  • Stop validateFlags mutating config as a side effect.

Scope

  • Every timeout/interval flag registration (StringVar -> Var).
  • timeoutFlagConfig/intervalFlagConfig field types (string -> time.Duration).
  • Both option builders (drop the re-parse).
  • The config-file loaders and formatConfigInfo default rendering.
  • Tests that currently assert string values such as "15s".
  • Unifying with the config layer's config.Duration (JSON/TOML/YAML) type is the substantive design work — there should be one canonical duration representation across flags and config.

Open questions to settle

pflag's built-in DurationVar cannot be reused because it rejects bare numbers. Follow-up from #284, which fixed the immediate bugs (bare-seconds normalization, positive validation, wiring --timeout-mcp-shutdown) and left this structural change as separate work.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions