* @author Maximum Software Inc * @license GPL-3.0-only * @link https://agenistrator.com/ * * SPDX-FileCopyrightText: 2025-2026 Alex Ruban * SPDX-FileCopyrightText: 2025-2026 Maximum Software Inc * SPDX-License-Identifier: GPL-3.0-only */ namespace Agenistrator; // Direct access prevention if ( ! defined( 'ABSPATH' ) ) { exit; } /** * List_Installed_Plugins_Tool class. */ class List_Installed_Plugins_Tool extends Tool { /** * Get the tool ID. * * @return string The tool ID. * @since 1.0.0 */ public function get_id() { return 'list_installed_plugins'; } /** * Get the tool name. * * @return string The tool name. * @since 1.0.0 */ public function get_name() { return __( 'List Installed Plugins', 'agenistrator' ); } /** * Get the tool description. * * @return string The tool description. * @since 1.0.0 */ public function get_description() { return 'List all installed plugins with their status.'; } /** * Get usage instructions for the LLM. * * @return string Instructions for using this tool. * @since 1.0.0 */ public function get_instructions() { return 'TRUNCATION NOTE: The `truncated_description` field is truncated for brevity. Use the `get_plugin_details` tool with the plugin file path to retrieve the full description.'; } /** * Get the parameters schema for this tool. * * @return array Parameters schema in JSON Schema format. * @since 1.0.0 */ public function get_parameters() { return array( 'type' => 'object', 'properties' => array( 'status' => array( 'type' => 'string', 'description' => 'Filter by status', 'enum' => array( 'all', 'active', 'inactive' ), 'default' => 'all', ), 'limit' => array( 'type' => 'integer', 'description' => 'Maximum number of plugins to return', 'default' => 100, ), 'offset' => array( 'type' => 'integer', 'description' => 'Number of plugins to skip', 'default' => 0, ), ), 'required' => array(), ); } /** * Check if the current user can execute this tool. * * @return bool True if the current user has permission. * @since 1.0.0 */ public function current_user_can_execute() { return current_user_can( 'activate_plugins' ); } /** * Check if this tool is read-only. * * @return bool True if the tool only reads data. * @since 1.0.0 */ public function is_read_only() { return true; } /** * Execute the tool with the given arguments. * * @param array $args The tool arguments. * * @return array The tool execution result. * @since 1.0.0 */ protected function execute( $args ) { if ( ! function_exists( 'get_plugins' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $all_plugins = get_plugins(); $active_plugins = get_option( 'active_plugins', array() ); $status_filter = $args['status'] ?? 'all'; $plugins = array(); foreach ( $all_plugins as $plugin_file => $plugin_data ) { $is_active = in_array( $plugin_file, $active_plugins, true ); if ( 'active' === $status_filter && ! $is_active ) { continue; } if ( 'inactive' === $status_filter && $is_active ) { continue; } $plugins[] = array( 'file' => $plugin_file, 'name' => $plugin_data['Name'], 'version' => $plugin_data['Version'], 'author' => $plugin_data['Author'], 'truncated_description' => String_Utils::truncate_to_token_boundary_with_ellipsis( $plugin_data['Description'], 200 ), 'is_active' => $is_active, ); } $limit = isset( $args['limit'] ) ? intval( $args['limit'] ) : 100; $offset = isset( $args['offset'] ) ? intval( $args['offset'] ) : 0; $total = count( $plugins ); $plugins = array_slice( $plugins, $offset, $limit ); return $this->success_response( 'Plugins retrieved successfully', array( 'plugins' => $plugins, 'count' => count( $plugins ), 'total' => $total, 'limit' => $limit, 'offset' => $offset, 'has_more' => ( $offset + count( $plugins ) ) < $total, ) ); } }