Add cache configuration to cli

Change-Id: I22b7eb9bd9a2fb9e7106ff20487e285638c5320f
diff --git a/config/cache.go b/config/cache.go
new file mode 100644
index 0000000..2e6ffaa
--- /dev/null
+++ b/config/cache.go
@@ -0,0 +1,100 @@
+package config
+
+import (
+	"fmt"
+	"time"
+)
+
+// CacheConfig configures the cache behavior
+type CacheConfig struct {
+	// Enabled controls whether caching is active
+	Enabled bool `yaml:"enabled" default:"true" help:"Enable response caching"`
+
+	// DefaultTTL is the default time-to-live for cache entries
+	DefaultTTL string `yaml:"default_ttl" default:"5m" help:"Default cache TTL (e.g., '5m', '1h')"`
+
+	// SearchTTL is the TTL for search results
+	SearchTTL string `yaml:"search_ttl" default:"2m" help:"Cache TTL for search results (e.g., '2m', '30s')"`
+
+	// MetadataTTL is the TTL for metadata and corpus information
+	MetadataTTL string `yaml:"metadata_ttl" default:"15m" help:"Cache TTL for metadata and corpus info (e.g., '15m', '1h')"`
+
+	// MaxSize is the maximum number of cache entries
+	MaxSize int `yaml:"max_size" default:"1000" help:"Maximum number of cache entries"`
+}
+
+// DefaultCacheConfig returns a default cache configuration
+func DefaultCacheConfig() *CacheConfig {
+	return &CacheConfig{
+		Enabled:     true,
+		DefaultTTL:  "5m",  // 5 minutes
+		SearchTTL:   "2m",  // 2 minutes - search results change less frequently
+		MetadataTTL: "15m", // 15 minutes - metadata is more stable
+		MaxSize:     1000,
+	}
+}
+
+// Validate validates cache configuration
+func (c *CacheConfig) Validate() error {
+	if !c.Enabled {
+		return nil // Skip validation if cache is disabled
+	}
+
+	if c.MaxSize <= 0 {
+		return fmt.Errorf("cache max_size must be positive, got %d", c.MaxSize)
+	}
+
+	// Validate TTL duration strings
+	if _, err := time.ParseDuration(c.DefaultTTL); err != nil {
+		return fmt.Errorf("invalid default_ttl '%s': %w", c.DefaultTTL, err)
+	}
+
+	if _, err := time.ParseDuration(c.SearchTTL); err != nil {
+		return fmt.Errorf("invalid search_ttl '%s': %w", c.SearchTTL, err)
+	}
+
+	if _, err := time.ParseDuration(c.MetadataTTL); err != nil {
+		return fmt.Errorf("invalid metadata_ttl '%s': %w", c.MetadataTTL, err)
+	}
+
+	return nil
+}
+
+// GetDefaultTTL returns the default TTL as a time.Duration
+func (c *CacheConfig) GetDefaultTTL() time.Duration {
+	if !c.Enabled {
+		return 0
+	}
+
+	duration, err := time.ParseDuration(c.DefaultTTL)
+	if err != nil {
+		return 5 * time.Minute // fallback to default
+	}
+	return duration
+}
+
+// GetSearchTTL returns the search TTL as a time.Duration
+func (c *CacheConfig) GetSearchTTL() time.Duration {
+	if !c.Enabled {
+		return 0
+	}
+
+	duration, err := time.ParseDuration(c.SearchTTL)
+	if err != nil {
+		return 2 * time.Minute // fallback to default
+	}
+	return duration
+}
+
+// GetMetadataTTL returns the metadata TTL as a time.Duration
+func (c *CacheConfig) GetMetadataTTL() time.Duration {
+	if !c.Enabled {
+		return 0
+	}
+
+	duration, err := time.ParseDuration(c.MetadataTTL)
+	if err != nil {
+		return 15 * time.Minute // fallback to default
+	}
+	return duration
+}