'', 'poll_timeout' => self::DEFAULT_POLL_TIMEOUT, 'poll_interval' => self::DEFAULT_POLL_INTERVAL, 'archive_after_run' => true, ); } /** * Returns all settings merged with defaults. * * @since 0.1.0 * * @return array{ * default_model: string, * poll_timeout: int, * poll_interval: int, * archive_after_run: bool * } */ public static function all(): array { $stored = get_option(self::OPTION_KEY, array()); if (!is_array($stored)) { $stored = array(); } // Drop legacy nested API key from in-memory merge (migration strips it from DB). unset($stored['api_key']); return array_merge(self::defaults(), $stored); } /** * Persists settings. * * @since 0.1.0 * * @param array $settings Settings to store. * @return bool */ public static function update(array $settings): bool { $current = self::all(); $merged = array_merge($current, $settings); $sanitized = array( 'default_model' => isset($merged['default_model']) ? sanitize_text_field((string) $merged['default_model']) : '', 'poll_timeout' => self::sanitizePositiveInt($merged['poll_timeout'] ?? self::DEFAULT_POLL_TIMEOUT, self::DEFAULT_POLL_TIMEOUT, 30, 600), 'poll_interval' => self::sanitizePositiveInt($merged['poll_interval'] ?? self::DEFAULT_POLL_INTERVAL, self::DEFAULT_POLL_INTERVAL, 1, 30), 'archive_after_run' => !empty($merged['archive_after_run']), ); return update_option(self::OPTION_KEY, $sanitized, false); } /** * Returns the configured default model ID. * * @since 0.1.0 */ public static function defaultModel(): string { $settings = self::all(); return isset($settings['default_model']) ? (string) $settings['default_model'] : ''; } /** * Returns poll timeout in seconds. * * @since 0.1.0 */ public static function pollTimeout(): int { $settings = self::all(); return (int) ($settings['poll_timeout'] ?? self::DEFAULT_POLL_TIMEOUT); } /** * Returns poll interval in seconds. * * @since 0.1.0 */ public static function pollInterval(): int { $settings = self::all(); return (int) ($settings['poll_interval'] ?? self::DEFAULT_POLL_INTERVAL); } /** * Whether agents should be archived after a successful run. * * @since 0.1.0 */ public static function archiveAfterRun(): bool { $settings = self::all(); return !empty($settings['archive_after_run']); } /** * Deletes plugin options. * * @since 0.1.0 */ public static function deleteAll(): void { delete_option(self::OPTION_KEY); } /** * Sanitizes a positive integer within bounds. * * @since 0.1.0 * * @param mixed $value Raw value. * @param int $default Default when invalid. * @param int $min Minimum allowed. * @param int $max Maximum allowed. */ private static function sanitizePositiveInt($value, int $default, int $min, int $max): int { $int = is_numeric($value) ? (int) $value : $default; if ($int < $min) { return $min; } if ($int > $max) { return $max; } return $int; } }