package config import ( "errors" "os" "path/filepath" "strconv" "time" ) type Config struct { TelegramToken string DatabasePath string CodexSocketPath string UploadDir string DefaultModel string DefaultSandbox string PollTimeout time.Duration AppVersion string } func Load() (Config, error) { wd, err := os.Getwd() if err != nil { return Config{}, err } cfg := Config{ TelegramToken: os.Getenv("TELEGRAM_BOT_TOKEN"), DatabasePath: envOr("DB_PATH", filepath.Join(wd, "data", "bot.db")), CodexSocketPath: envOr("HOST_CODEX_SOCKET", filepath.Join(wd, "run", "codex.sock")), UploadDir: envOr("HOST_UPLOAD_DIR", filepath.Join(wd, "uploads")), DefaultModel: os.Getenv("DEFAULT_MODEL"), DefaultSandbox: envOr("DEFAULT_SANDBOX", "workspace-write"), PollTimeout: durationSeconds("POLL_TIMEOUT_SECONDS", 30), AppVersion: envOr("APP_VERSION", "0.1.0"), } if cfg.TelegramToken == "" { return Config{}, errors.New("TELEGRAM_BOT_TOKEN is required") } return cfg, nil } func envOr(key, fallback string) string { if value := os.Getenv(key); value != "" { return value } return fallback } func durationSeconds(key string, fallback int) time.Duration { raw := os.Getenv(key) if raw == "" { return time.Duration(fallback) * time.Second } value, err := strconv.Atoi(raw) if err != nil || value <= 0 { return time.Duration(fallback) * time.Second } return time.Duration(value) * time.Second }