diff --git a/inc/Abilities/AgentAbilities.php b/inc/Abilities/AgentAbilities.php index e57c8cc7..6403655e 100644 --- a/inc/Abilities/AgentAbilities.php +++ b/inc/Abilities/AgentAbilities.php @@ -546,7 +546,7 @@ public static function getAgent( array $input ): array { 'owner_id' => (int) $agent['owner_id'], 'agent_config' => is_array( $agent['agent_config'] ?? null ) ? $agent['agent_config'] - : ( json_decode( $agent['agent_config'] ?? '{}', true ) ?: array() ), + : ( json_decode( $agent['agent_config'] ?? '{}', true ) ? json_decode( $agent['agent_config'] ?? '{}', true ) : array() ), 'status' => (string) $agent['status'], 'created_at' => $agent['created_at'] ?? '', 'updated_at' => $agent['updated_at'] ?? '', @@ -693,7 +693,7 @@ public static function deleteAgent( array $input ): array { if ( $file->isDir() ) { rmdir( $file->getRealPath() ); } else { - unlink( $file->getRealPath() ); + wp_delete_file( $file->getRealPath( ) ); } } rmdir( $agent_dir ); diff --git a/inc/Abilities/AgentMemoryAbilities.php b/inc/Abilities/AgentMemoryAbilities.php index 65bd2da4..01231e86 100644 --- a/inc/Abilities/AgentMemoryAbilities.php +++ b/inc/Abilities/AgentMemoryAbilities.php @@ -235,7 +235,7 @@ public static function getMemory( array $input ): array { $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $memory = new AgentMemory( $user_id, $agent_id ); - $section = $input['section'] ?? null; + $section = $input['section'] ?? null; if ( null === $section || '' === $section ) { return $memory->get_all(); @@ -254,9 +254,9 @@ public static function updateMemory( array $input ): array { $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $memory = new AgentMemory( $user_id, $agent_id ); - $section = $input['section']; - $content = $input['content']; - $mode = $input['mode']; + $section = $input['section']; + $content = $input['content']; + $mode = $input['mode']; if ( 'append' === $mode ) { return $memory->append_to_section( $section, $content ); @@ -275,8 +275,8 @@ public static function searchMemory( array $input ): array { $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $memory = new AgentMemory( $user_id, $agent_id ); - $query = $input['query']; - $section = $input['section'] ?? null; + $query = $input['query']; + $section = $input['section'] ?? null; return $memory->search( $query, $section ); } diff --git a/inc/Abilities/Chat/CreateChatSessionAbility.php b/inc/Abilities/Chat/CreateChatSessionAbility.php index 622317b9..9ec15b74 100644 --- a/inc/Abilities/Chat/CreateChatSessionAbility.php +++ b/inc/Abilities/Chat/CreateChatSessionAbility.php @@ -41,24 +41,24 @@ private function registerAbility(): void { 'input_schema' => array( 'type' => 'object', 'properties' => array( - 'user_id' => array( + 'user_id' => array( 'type' => 'integer', 'description' => __( 'User ID who owns the session.', 'data-machine' ), ), - 'agent_id' => array( + 'agent_id' => array( 'type' => 'integer', 'description' => __( 'First-class agent ID for this session.', 'data-machine' ), ), - 'context' => array( + 'context' => array( 'type' => 'string', 'default' => 'chat', 'description' => __( 'Execution context (chat, pipeline, system).', 'data-machine' ), ), - 'source' => array( + 'source' => array( 'type' => 'string', 'description' => __( 'Session source identifier (e.g. ping, chat).', 'data-machine' ), ), - 'metadata' => array( + 'metadata' => array( 'type' => 'object', 'description' => __( 'Additional metadata for the session.', 'data-machine' ), ), diff --git a/inc/Abilities/Chat/ListChatSessionsAbility.php b/inc/Abilities/Chat/ListChatSessionsAbility.php index 6c97c7c3..63d399c0 100644 --- a/inc/Abilities/Chat/ListChatSessionsAbility.php +++ b/inc/Abilities/Chat/ListChatSessionsAbility.php @@ -40,25 +40,25 @@ private function registerAbility(): void { 'input_schema' => array( 'type' => 'object', 'properties' => array( - 'user_id' => array( + 'user_id' => array( 'type' => 'integer', 'description' => __( 'User ID to list sessions for.', 'data-machine' ), ), - 'agent_id' => array( + 'agent_id' => array( 'type' => array( 'integer', 'null' ), 'description' => __( 'Agent ID to filter sessions by. Null or omitted returns all agents.', 'data-machine' ), ), - 'limit' => array( + 'limit' => array( 'type' => 'integer', 'default' => 20, 'description' => __( 'Maximum sessions to return (1-100).', 'data-machine' ), ), - 'offset' => array( + 'offset' => array( 'type' => 'integer', 'default' => 0, 'description' => __( 'Pagination offset.', 'data-machine' ), ), - 'context' => array( + 'context' => array( 'type' => 'string', 'description' => __( 'Context filter (chat, pipeline, system).', 'data-machine' ), ), @@ -68,16 +68,16 @@ private function registerAbility(): void { 'output_schema' => array( 'type' => 'object', 'properties' => array( - 'success' => array( 'type' => 'boolean' ), - 'sessions' => array( + 'success' => array( 'type' => 'boolean' ), + 'sessions' => array( 'type' => 'array', 'items' => array( 'type' => 'object' ), ), - 'total' => array( 'type' => 'integer' ), - 'limit' => array( 'type' => 'integer' ), - 'offset' => array( 'type' => 'integer' ), - 'context' => array( 'type' => 'string' ), - 'error' => array( 'type' => 'string' ), + 'total' => array( 'type' => 'integer' ), + 'limit' => array( 'type' => 'integer' ), + 'offset' => array( 'type' => 'integer' ), + 'context' => array( 'type' => 'string' ), + 'error' => array( 'type' => 'string' ), ), ), 'execute_callback' => array( $this, 'execute' ), @@ -132,12 +132,12 @@ public function execute( array $input ): array { $total = $this->chat_db->get_user_session_count( $user_id, $context, $agent_id ); return array( - 'success' => true, - 'sessions' => $sessions, - 'total' => $total, - 'limit' => $limit, - 'offset' => $offset, - 'context' => $context, + 'success' => true, + 'sessions' => $sessions, + 'total' => $total, + 'limit' => $limit, + 'offset' => $offset, + 'context' => $context, ); } } diff --git a/inc/Abilities/DailyMemoryAbilities.php b/inc/Abilities/DailyMemoryAbilities.php index 008365df..1bc68d20 100644 --- a/inc/Abilities/DailyMemoryAbilities.php +++ b/inc/Abilities/DailyMemoryAbilities.php @@ -253,7 +253,7 @@ public static function readDaily( array $input ): array { $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $daily = new DailyMemory( $user_id, $agent_id ); - $date = $input['date'] ?? gmdate( 'Y-m-d' ); + $date = $input['date'] ?? gmdate( 'Y-m-d' ); $parts = DailyMemory::parse_date( $date ); if ( ! $parts ) { @@ -284,8 +284,8 @@ public static function writeDaily( array $input ): array { $agent_id = (int) ( $input['agent_id'] ?? 0 ); $daily = new DailyMemory( $user_id, $agent_id ); $content = $input['content']; - $date = $input['date'] ?? gmdate( 'Y-m-d' ); - $mode = $input['mode'] ?? 'append'; + $date = $input['date'] ?? gmdate( 'Y-m-d' ); + $mode = $input['mode'] ?? 'append'; $parts = DailyMemory::parse_date( $date ); if ( ! $parts ) { @@ -325,9 +325,9 @@ public static function searchDaily( array $input ): array { $user_id = (int) ( $input['user_id'] ?? 0 ); $agent_id = (int) ( $input['agent_id'] ?? 0 ); $daily = new DailyMemory( $user_id, $agent_id ); - $query = $input['query']; - $from = $input['from'] ?? null; - $to = $input['to'] ?? null; + $query = $input['query']; + $from = $input['from'] ?? null; + $to = $input['to'] ?? null; return $daily->search( $query, $from, $to ); } diff --git a/inc/Abilities/DuplicateCheck/DuplicateCheckAbility.php b/inc/Abilities/DuplicateCheck/DuplicateCheckAbility.php index 43a8f0dd..5361ff9c 100644 --- a/inc/Abilities/DuplicateCheck/DuplicateCheckAbility.php +++ b/inc/Abilities/DuplicateCheck/DuplicateCheckAbility.php @@ -70,36 +70,36 @@ private function registerCheckDuplicate(): void { 'type' => 'object', 'required' => array( 'title' ), 'properties' => array( - 'title' => array( + 'title' => array( 'type' => 'string', 'description' => __( 'Title or topic to check for duplicates', 'data-machine' ), ), - 'post_type' => array( + 'post_type' => array( 'type' => 'string', 'description' => __( 'WordPress post type to check against (default: "post")', 'data-machine' ), ), - 'lookback_days' => array( + 'lookback_days' => array( 'type' => 'integer', 'description' => __( 'How many days back to search (default: 14)', 'data-machine' ), ), - 'scope' => array( + 'scope' => array( 'type' => 'string', 'enum' => array( 'published', 'queue', 'both' ), 'description' => __( 'What to check: published posts, queue items, or both (default: "published")', 'data-machine' ), ), - 'flow_id' => array( + 'flow_id' => array( 'type' => 'integer', 'description' => __( 'Flow ID for queue check (required when scope includes queue)', 'data-machine' ), ), - 'flow_step_id' => array( + 'flow_step_id' => array( 'type' => 'string', 'description' => __( 'Flow step ID for queue check (required when scope includes queue)', 'data-machine' ), ), - 'threshold' => array( + 'threshold' => array( 'type' => 'number', 'description' => __( 'Jaccard similarity threshold for queue checks (default: 0.65)', 'data-machine' ), ), - 'context' => array( + 'context' => array( 'type' => 'object', 'description' => __( 'Domain-specific context for extension strategies (e.g., venue, startDate, ticketUrl for events)', 'data-machine' ), ), @@ -478,8 +478,8 @@ private function checkQueueItems( string $title, float $threshold, int $flow_id, 'info', 'DuplicateCheck: found matching queue item', array( - 'title' => $title, - 'match' => $best_match, + 'title' => $title, + 'match' => $best_match, ) ); diff --git a/inc/Abilities/InternalLinkingAbilities.php b/inc/Abilities/InternalLinkingAbilities.php index cbf46587..1a67ba19 100644 --- a/inc/Abilities/InternalLinkingAbilities.php +++ b/inc/Abilities/InternalLinkingAbilities.php @@ -1104,15 +1104,15 @@ private static function buildLinkGraph( string $post_type, string $category, arr $inbound_total = array_sum( $inbound ); return array( - 'success' => true, - 'post_type' => $post_type, - 'total_scanned' => $total_scanned, - 'total_links' => $total_links, - 'orphaned_count' => count( $orphaned ), - 'avg_outbound' => $total_scanned > 0 ? round( $outbound_total / $total_scanned, 2 ) : 0, - 'avg_inbound' => $total_scanned > 0 ? round( $inbound_total / $total_scanned, 2 ) : 0, - 'orphaned_posts' => $orphaned, - 'top_linked' => $top_linked, + 'success' => true, + 'post_type' => $post_type, + 'total_scanned' => $total_scanned, + 'total_links' => $total_links, + 'orphaned_count' => count( $orphaned ), + 'avg_outbound' => $total_scanned > 0 ? round( $outbound_total / $total_scanned, 2 ) : 0, + 'avg_inbound' => $total_scanned > 0 ? round( $inbound_total / $total_scanned, 2 ) : 0, + 'orphaned_posts' => $orphaned, + 'top_linked' => $top_linked, // Internal data for broken link checker (not exposed in REST). '_all_links' => $all_links, '_all_external_links' => $all_external_links, diff --git a/inc/Abilities/LogAbilities.php b/inc/Abilities/LogAbilities.php index a83ad826..0a3905cc 100644 --- a/inc/Abilities/LogAbilities.php +++ b/inc/Abilities/LogAbilities.php @@ -235,14 +235,14 @@ private function registerAbilities(): void { 'output_schema' => array( 'type' => 'object', 'properties' => array( - 'success' => array( 'type' => 'boolean' ), - 'file' => array( 'type' => 'string' ), - 'entries' => array( 'type' => 'array' ), - 'total' => array( 'type' => 'integer' ), - 'filtered' => array( 'type' => 'integer' ), - 'file_size' => array( 'type' => 'integer' ), + 'success' => array( 'type' => 'boolean' ), + 'file' => array( 'type' => 'string' ), + 'entries' => array( 'type' => 'array' ), + 'total' => array( 'type' => 'integer' ), + 'filtered' => array( 'type' => 'integer' ), + 'file_size' => array( 'type' => 'integer' ), 'last_modified' => array( 'type' => 'string' ), - 'error' => array( 'type' => 'string' ), + 'error' => array( 'type' => 'string' ), ), ), 'execute_callback' => array( self::class, 'readDebugLog' ), @@ -471,7 +471,7 @@ public static function readDebugLog( array $input ): array { // Filter by search. if ( $search ) { $search_lower = strtolower( $search ); - $parsed = array_filter( $parsed, function ( $entry ) use ( $search_lower ) { + $parsed = array_filter( $parsed, function ( $entry ) use ( $search_lower ) { return str_contains( strtolower( $entry['message'] ), $search_lower ) || str_contains( strtolower( $entry['file'] ?? '' ), $search_lower ); }); @@ -517,7 +517,7 @@ private static function tailDebugLog( string $file, int $lines ): array { $line_buffer = ''; while ( $pos > 0 && count( $found_lines ) < $lines ) { - $pos--; + --$pos; fseek( $handle, $pos, SEEK_SET ); $char = fgetc( $handle ); @@ -569,13 +569,13 @@ private static function parseDebugLogLine( string $line ): ?array { $message_part = $matches[3]; // Parse timestamp (WordPress format: 01-Jan-2026 12:34:56+00:00). - $timestamp = strtotime( $timestamp_str ) ?: 0; + $timestamp = strtotime( $timestamp_str ) ? strtotime( $timestamp_str ) : 0; // Extract file and line from message if present. - $file = null; + $file = null; $line_number = null; if ( preg_match( '/in\s+(.+\.php)(?:\s+on\s+line\s+(\d+))?$/i', $message_part, $file_matches ) ) { - $file = $file_matches[1]; + $file = $file_matches[1]; $line_number = isset( $file_matches[2] ) ? (int) $file_matches[2] : null; // Remove file/line from message for cleaner output. $message_part = trim( preg_replace( '/\s*in\s+.+\.php(?:\s+on\s+line\s+\d+)?$/i', '', $message_part ) ); @@ -630,24 +630,24 @@ private static function normalizeLogLevel( string $level ): string { $level = strtoupper( trim( $level ) ); $map = array( - 'FATAL ERROR' => 'FATAL', - 'FATAL' => 'FATAL', - 'ERROR' => 'ERROR', - 'WARNING' => 'WARNING', - 'PARSE ERROR' => 'PARSE', - 'PARSE' => 'PARSE', - 'NOTICE' => 'NOTICE', - 'STRICT' => 'NOTICE', - 'DEPRECATED' => 'DEPRECATED', - 'CORE ERROR' => 'FATAL', - 'CORE WARNING' => 'WARNING', - 'COMPILE ERROR' => 'FATAL', - 'COMPILE WARNING' => 'WARNING', - 'USER ERROR' => 'ERROR', - 'USER WARNING' => 'WARNING', - 'USER NOTICE' => 'NOTICE', - 'USER DEPRECATED' => 'DEPRECATED', - 'RECOVERABLE ERROR' => 'ERROR', + 'FATAL ERROR' => 'FATAL', + 'FATAL' => 'FATAL', + 'ERROR' => 'ERROR', + 'WARNING' => 'WARNING', + 'PARSE ERROR' => 'PARSE', + 'PARSE' => 'PARSE', + 'NOTICE' => 'NOTICE', + 'STRICT' => 'NOTICE', + 'DEPRECATED' => 'DEPRECATED', + 'CORE ERROR' => 'FATAL', + 'CORE WARNING' => 'WARNING', + 'COMPILE ERROR' => 'FATAL', + 'COMPILE WARNING' => 'WARNING', + 'USER ERROR' => 'ERROR', + 'USER WARNING' => 'WARNING', + 'USER NOTICE' => 'NOTICE', + 'USER DEPRECATED' => 'DEPRECATED', + 'RECOVERABLE ERROR' => 'ERROR', 'CATCHABLE FATAL ERROR' => 'ERROR', ); diff --git a/inc/Abilities/Media/ImageOptimizationAbilities.php b/inc/Abilities/Media/ImageOptimizationAbilities.php index 142b9e6c..6e534d2a 100644 --- a/inc/Abilities/Media/ImageOptimizationAbilities.php +++ b/inc/Abilities/Media/ImageOptimizationAbilities.php @@ -75,7 +75,7 @@ private function registerAbilities(): void { 'total_size' => array( 'type' => 'integer' ), 'oversized_count' => array( 'type' => 'integer' ), 'missing_webp_count' => array( 'type' => 'integer' ), - 'potential_savings' => array( 'type' => 'integer' ), + 'potential_savings' => array( 'type' => 'integer' ), 'oversized_images' => array( 'type' => 'array', 'items' => array( 'type' => 'object' ), @@ -180,7 +180,7 @@ public static function diagnoseImages( array $input = array() ): array { $total_size = 0; $oversized_count = 0; $missing_webp_count = 0; - $potential_savings = 0; + $potential_savings = 0; $oversized_images = array(); foreach ( $attachments as $attachment_id ) { @@ -189,14 +189,14 @@ public static function diagnoseImages( array $input = array() ): array { continue; } - $file_size = filesize( $file_path ); + $file_size = filesize( $file_path ); $total_size += $file_size; - $metadata = wp_get_attachment_metadata( $attachment_id ); - $mime_type = get_post_mime_type( $attachment_id ); + $metadata = wp_get_attachment_metadata( $attachment_id ); + $mime_type = get_post_mime_type( $attachment_id ); // Check for WebP variant. - $has_webp = false; - $webp_path = preg_replace( '/\.(jpe?g|png|gif)$/i', '.webp', $file_path ); + $has_webp = false; + $webp_path = preg_replace( '/\.(jpe?g|png|gif)$/i', '.webp', $file_path ); if ( file_exists( $webp_path ) ) { $has_webp = true; } @@ -220,7 +220,7 @@ public static function diagnoseImages( array $input = array() ): array { ++$oversized_count; // Estimate savings (target ~60% reduction for heavily oversized). - $estimated_savings = (int) ( $file_size * 0.4 ); + $estimated_savings = (int) ( $file_size * 0.4 ); $potential_savings += $estimated_savings; $width = $metadata['width'] ?? 0; @@ -242,17 +242,17 @@ public static function diagnoseImages( array $input = array() ): array { usort( $oversized_images, fn( $a, $b ) => $b['file_size'] - $a['file_size'] ); return array( - 'success' => true, - 'total_images' => count( $attachments ), - 'total_size' => $total_size, - 'total_size_hr' => size_format( $total_size ), - 'oversized_count' => $oversized_count, - 'missing_webp_count' => $missing_webp_count, - 'potential_savings' => $potential_savings, + 'success' => true, + 'total_images' => count( $attachments ), + 'total_size' => $total_size, + 'total_size_hr' => size_format( $total_size ), + 'oversized_count' => $oversized_count, + 'missing_webp_count' => $missing_webp_count, + 'potential_savings' => $potential_savings, 'potential_savings_hr' => size_format( $potential_savings ), - 'size_threshold' => $size_threshold, - 'size_threshold_hr' => size_format( $size_threshold ), - 'oversized_images' => $oversized_images, + 'size_threshold' => $size_threshold, + 'size_threshold_hr' => size_format( $size_threshold ), + 'oversized_images' => $oversized_images, ); } @@ -329,11 +329,11 @@ public static function optimizeImages( array $input = array() ): array { } return array( - 'success' => true, - 'queued_count' => 0, - 'dry_run' => true, + 'success' => true, + 'queued_count' => 0, + 'dry_run' => true, 'would_optimize' => $preview, - 'message' => sprintf( '%d image(s) would be optimized (dry run).', count( $preview ) ), + 'message' => sprintf( '%d image(s) would be optimized (dry run).', count( $preview ) ), ); } diff --git a/inc/Abilities/Media/MediaAbilities.php b/inc/Abilities/Media/MediaAbilities.php index dcd265eb..e11c511e 100644 --- a/inc/Abilities/Media/MediaAbilities.php +++ b/inc/Abilities/Media/MediaAbilities.php @@ -71,23 +71,23 @@ private function registerUploadMedia(): void { 'input_schema' => array( 'type' => 'object', 'properties' => array( - 'url' => array( + 'url' => array( 'type' => 'string', 'description' => 'Remote URL to fetch media from. Either url or file_path is required.', ), - 'file_path' => array( + 'file_path' => array( 'type' => 'string', 'description' => 'Local file path of an already-downloaded media file. Either url or file_path is required.', ), - 'filename' => array( + 'filename' => array( 'type' => 'string', 'description' => 'Desired filename for storage (default: derived from URL or file_path).', ), - 'pipeline_id' => array( + 'pipeline_id' => array( 'type' => 'integer', 'description' => 'Pipeline ID for file organization in the repository.', ), - 'flow_id' => array( + 'flow_id' => array( 'type' => 'integer', 'description' => 'Flow ID for file organization in the repository.', ), @@ -262,8 +262,8 @@ public function executeValidateMedia( array $input ): array { ); } - $validator = $this->resolveValidator( $path, $media_type ); - $detected = $validator instanceof VideoValidator ? 'video' : 'image'; + $validator = $this->resolveValidator( $path, $media_type ); + $detected = $validator instanceof VideoValidator ? 'video' : 'image'; // If no constraints provided, do basic validation only. if ( empty( $constraints ) ) { @@ -279,7 +279,7 @@ public function executeValidateMedia( array $input ): array { // Constraint-based validation. For video, get metadata for duration/codec checks. $metadata = array(); - if ( $detected === 'video' ) { + if ( 'video' === $detected ) { $metadata = VideoMetadata::extract( $path ); } @@ -338,8 +338,8 @@ private function uploadFromUrl( string $url, string $filename, array $input ): a $flow_id = (int) ( $input['flow_id'] ?? 0 ); $context = array( - 'pipeline_id' => $pipeline_id ?: 'direct', - 'flow_id' => $flow_id ?: 'media-upload', + 'pipeline_id' => $pipeline_id ? $pipeline_id : 'direct', + 'flow_id' => $flow_id ? $flow_id : 'media-upload', ); $downloader = new RemoteFileDownloader(); diff --git a/inc/Abilities/SettingsAbilities.php b/inc/Abilities/SettingsAbilities.php index 2decf3c2..ee9f1662 100644 --- a/inc/Abilities/SettingsAbilities.php +++ b/inc/Abilities/SettingsAbilities.php @@ -71,12 +71,12 @@ private function registerGetSettings(): void { 'output_schema' => array( 'type' => 'object', 'properties' => array( - 'success' => array( 'type' => 'boolean' ), - 'settings' => array( 'type' => 'object' ), - 'defaults' => array( 'type' => 'object' ), + 'success' => array( 'type' => 'boolean' ), + 'settings' => array( 'type' => 'object' ), + 'defaults' => array( 'type' => 'object' ), 'network_settings' => array( 'type' => 'object' ), - 'global_tools' => array( 'type' => 'object' ), - 'error' => array( 'type' => 'string' ), + 'global_tools' => array( 'type' => 'object' ), + 'error' => array( 'type' => 'string' ), ), ), 'execute_callback' => array( $this, 'executeGetSettings' ), @@ -574,7 +574,7 @@ public function executeUpdateSettings( array $input ): array { } if ( is_array( $raw_network_context_models ) ) { - $valid_context_ids = array_column( PluginSettings::getContexts(), 'id' ); + $valid_context_ids = array_column( PluginSettings::getContexts(), 'id' ); $network_context_models = array(); foreach ( $raw_network_context_models as $context => $config ) { if ( in_array( $context, $valid_context_ids, true ) && is_array( $config ) ) { @@ -624,8 +624,8 @@ public function executeUpdateSettings( array $input ): array { PluginSettings::clearCache(); // Identify unhandled keys so callers know if something was ignored. - $input_keys = array_keys( $input ); - $unhandled = array_diff( $input_keys, $handled_keys ); + $input_keys = array_keys( $input ); + $unhandled = array_diff( $input_keys, $handled_keys ); $result = array( 'success' => true, diff --git a/inc/Abilities/SystemAbilities.php b/inc/Abilities/SystemAbilities.php index 364b4e8e..9aca2680 100644 --- a/inc/Abilities/SystemAbilities.php +++ b/inc/Abilities/SystemAbilities.php @@ -628,10 +628,10 @@ private static function generateAITitle( string $first_user_message, ?string $fi 'error', 'Session title AI generation failed', array( - 'error' => $response['error'] ?? 'Unknown error', - 'context' => 'system', - ) - ); + 'error' => $response['error'] ?? 'Unknown error', + 'context' => 'system', + ) + ); return null; } diff --git a/inc/Api/Chat/Chat.php b/inc/Api/Chat/Chat.php index 0cbbbd47..8d49c138 100644 --- a/inc/Api/Chat/Chat.php +++ b/inc/Api/Chat/Chat.php @@ -188,21 +188,21 @@ public static function register_routes() { 'callback' => array( self::class, 'list_sessions' ), 'permission_callback' => $chat_permission_callback, 'args' => array( - 'limit' => array( + 'limit' => array( 'type' => 'integer', 'required' => false, 'default' => 20, 'description' => __( 'Maximum sessions to return', 'data-machine' ), 'sanitize_callback' => 'absint', ), - 'offset' => array( + 'offset' => array( 'type' => 'integer', 'required' => false, 'default' => 0, 'description' => __( 'Pagination offset', 'data-machine' ), 'sanitize_callback' => 'absint', ), - 'context' => array( + 'context' => array( 'type' => 'string', 'required' => false, 'description' => __( 'Context filter (chat, pipeline, system)', 'data-machine' ), @@ -211,7 +211,7 @@ public static function register_routes() { return in_array( $param, array( 'chat', 'pipeline', 'system' ), true ); }, ), - 'agent_id' => array( + 'agent_id' => array( 'type' => 'integer', 'required' => false, 'description' => __( 'Filter sessions by agent ID', 'data-machine' ), @@ -330,11 +330,11 @@ public static function list_sessions( WP_REST_Request $request ) { if ( $ability ) { $result = $ability->execute( array( - 'user_id' => get_current_user_id(), - 'agent_id' => $agent_id, - 'limit' => (int) $request->get_param( 'limit' ), - 'offset' => (int) $request->get_param( 'offset' ), - 'context' => $request->get_param( 'context' ), + 'user_id' => get_current_user_id(), + 'agent_id' => $agent_id, + 'limit' => (int) $request->get_param( 'limit' ), + 'offset' => (int) $request->get_param( 'offset' ), + 'context' => $request->get_param( 'context' ), ) ); @@ -360,11 +360,11 @@ public static function list_sessions( WP_REST_Request $request ) { array( 'success' => true, 'data' => array( - 'sessions' => $sessions, - 'total' => $total, - 'limit' => $limit, - 'offset' => $offset, - 'context' => $context, + 'sessions' => $sessions, + 'total' => $total, + 'limit' => $limit, + 'offset' => $offset, + 'context' => $context, ), ) ); diff --git a/inc/Api/Chat/ChatOrchestrator.php b/inc/Api/Chat/ChatOrchestrator.php index 671721ef..795e7452 100644 --- a/inc/Api/Chat/ChatOrchestrator.php +++ b/inc/Api/Chat/ChatOrchestrator.php @@ -392,7 +392,7 @@ public static function processPing( string $message, string $provider, string $m $model, array( 'context' => 'chat', - 'user_id' => $user_id, + 'user_id' => $user_id, ) ); @@ -460,9 +460,9 @@ private static function createSession( int $user_id, string $source = '' ): stri if ( $ability ) { $input = array( - 'user_id' => $user_id, - 'agent_id' => $agent_id, - 'context' => 'chat', + 'user_id' => $user_id, + 'agent_id' => $agent_id, + 'context' => 'chat', ); if ( $source ) { @@ -549,14 +549,14 @@ public static function executeConversationTurn( $chat_db = new ChatDatabase(); try { - $user_id = $options['user_id'] ?? 0; + $user_id = $options['user_id'] ?? 0; if ( $agent_id <= 0 && $user_id > 0 && function_exists( 'datamachine_resolve_or_create_agent_id' ) ) { $agent_id = datamachine_resolve_or_create_agent_id( $user_id ); } - $resolver = new ToolPolicyResolver(); - $all_tools = $resolver->resolve( array( + $resolver = new ToolPolicyResolver(); + $all_tools = $resolver->resolve( array( 'context' => ToolPolicyResolver::CONTEXT_CHAT, 'agent_id' => $agent_id, ) ); diff --git a/inc/Api/Chat/Tools/ManageLogs.php b/inc/Api/Chat/Tools/ManageLogs.php index 406371d6..0885a033 100644 --- a/inc/Api/Chat/Tools/ManageLogs.php +++ b/inc/Api/Chat/Tools/ManageLogs.php @@ -34,17 +34,17 @@ public function getToolDefinition(): array { 'method' => 'handle_tool_call', 'description' => $this->buildDescription(), 'parameters' => array( - 'action' => array( + 'action' => array( 'type' => 'string', 'required' => true, 'description' => 'Action to perform: "clear" or "get_metadata"', ), - 'agent_id' => array( + 'agent_id' => array( 'type' => 'integer', 'required' => false, 'description' => 'Agent ID to target. Omit to target all logs.', ), - 'context' => array( + 'context' => array( 'type' => 'string', 'required' => false, 'description' => 'Deprecated label only. Use agent_id instead.', diff --git a/inc/Api/Flows/Flows.php b/inc/Api/Flows/Flows.php index 4bc7ab7d..de495d44 100644 --- a/inc/Api/Flows/Flows.php +++ b/inc/Api/Flows/Flows.php @@ -640,8 +640,8 @@ public static function handle_get_memory_files( $request ) { ); } - $memory_files = $db_flows->get_flow_memory_files( $flow_id ); - $daily_memory = $db_flows->get_flow_daily_memory( $flow_id ); + $memory_files = $db_flows->get_flow_memory_files( $flow_id ); + $daily_memory = $db_flows->get_flow_daily_memory( $flow_id ); return rest_ensure_response( array( @@ -663,10 +663,10 @@ public static function handle_get_memory_files( $request ) { * @return \WP_REST_Response|\WP_Error Response. */ public static function handle_update_memory_files( $request ) { - $flow_id = (int) $request->get_param( 'flow_id' ); - $params = $request->get_json_params(); - $memory_files = $params['memory_files'] ?? array(); - $daily_memory = $params['daily_memory'] ?? null; + $flow_id = (int) $request->get_param( 'flow_id' ); + $params = $request->get_json_params(); + $memory_files = $params['memory_files'] ?? array(); + $daily_memory = $params['daily_memory'] ?? null; $db_flows = new \DataMachine\Core\Database\Flows\Flows(); $flow = $db_flows->get_flow( $flow_id ); @@ -743,7 +743,7 @@ private static function sanitize_daily_memory( array $config ): array { break; case 'specific_dates': - $dates = $config['dates'] ?? array(); + $dates = $config['dates'] ?? array(); $sanitized['dates'] = array_values( array_filter( array_map( @@ -768,7 +768,7 @@ function ( $date ) { break; case 'months': - $months = $config['months'] ?? array(); + $months = $config['months'] ?? array(); $sanitized['months'] = array_values( array_filter( array_map( diff --git a/inc/Api/Providers.php b/inc/Api/Providers.php index a2785623..62c4d6c6 100644 --- a/inc/Api/Providers.php +++ b/inc/Api/Providers.php @@ -93,9 +93,9 @@ public static function handle_get_providers() { array( 'success' => true, 'data' => array( - 'providers' => $providers, - 'defaults' => $defaults, - 'contexts' => $contexts, + 'providers' => $providers, + 'defaults' => $defaults, + 'contexts' => $contexts, 'context_models' => $context_models, ), ) diff --git a/inc/Api/System/System.php b/inc/Api/System/System.php index 8a94f565..50e4d6df 100644 --- a/inc/Api/System/System.php +++ b/inc/Api/System/System.php @@ -198,8 +198,8 @@ public static function get_status( WP_REST_Request $request ) { */ public static function get_tasks( WP_REST_Request $request ) { $request; - $registry = TaskRegistry::getRegistry(); - $last_runs = self::get_last_runs( array_keys( $registry ) ); + $registry = TaskRegistry::getRegistry(); + $last_runs = self::get_last_runs( array_keys( $registry ) ); // Merge last-run data into each task entry. $tasks = array(); @@ -451,7 +451,7 @@ private static function resolve_prompt_definition( string $task_type, string $pr if ( ! isset( $definitions[ $prompt_key ] ) ) { return new WP_Error( 'invalid_prompt_key', - sprintf( __( 'Unknown prompt key "%s" for task type "%s".', 'data-machine' ), $prompt_key, $task_type ), + sprintf( __( 'Unknown prompt key "%1$s" for task type "%2$s".', 'data-machine' ), $prompt_key, $task_type ), array( 'status' => 404 ) ); } @@ -505,7 +505,7 @@ private static function get_last_runs( array $task_types ): array { // phpcs:enable WordPress.DB.PreparedSQL if ( $row ) { - $row['run_count'] = (int) $count; + $row['run_count'] = (int) $count; $results[ $task_type ] = $row; } elseif ( $count > 0 ) { $results[ $task_type ] = array( diff --git a/inc/Cli/Commands/ChatCommand.php b/inc/Cli/Commands/ChatCommand.php index 1652b32a..8b945b64 100644 --- a/inc/Cli/Commands/ChatCommand.php +++ b/inc/Cli/Commands/ChatCommand.php @@ -75,7 +75,7 @@ public function list_sessions( array $args, array $assoc_args ): void { $offset = max( 0, (int) ( $assoc_args['offset'] ?? 0 ) ); $context = ! empty( $assoc_args['context'] ) ? sanitize_text_field( $assoc_args['context'] ) : null; - $chat_db = new ChatDatabase(); + $chat_db = new ChatDatabase(); $sessions = $chat_db->get_user_sessions( $user_id, $limit, $offset, $context ); $total = $chat_db->get_user_session_count( $user_id, $context ); @@ -87,13 +87,13 @@ public function list_sessions( array $args, array $assoc_args ): void { // Flatten for display. $display_items = array(); foreach ( $sessions as $session ) { - $metadata = $session['metadata'] ?? array(); + $metadata = $session['metadata'] ?? array(); $display_items[] = array( - 'session_id' => $session['session_id'], - 'title' => $session['title'] ?? '(untitled)', - 'context' => $session['context'] ?? 'chat', + 'session_id' => $session['session_id'], + 'title' => $session['title'] ?? '(untitled)', + 'context' => $session['context'] ?? 'chat', 'message_count' => $metadata['message_count'] ?? 0, - 'created_at' => $metadata['started_at'] ?? $session['created_at'] ?? '-', + 'created_at' => $metadata['started_at'] ?? $session['created_at'] ?? '-', ); } @@ -170,11 +170,11 @@ public function get( array $args, array $assoc_args ): void { WP_CLI::log( WP_CLI::colorize( '%BSession Metadata:%n' ) ); WP_CLI::log( " Session ID: {$session['session_id']}" ); - WP_CLI::log( " Title: " . ( $session['title'] ?? '(untitled)' ) ); - WP_CLI::log( " Context: " . ( $session['context'] ?? 'chat' ) ); + WP_CLI::log( ' Title: ' . ( $session['title'] ?? '(untitled)' ) ); + WP_CLI::log( ' Context: ' . ( $session['context'] ?? 'chat' ) ); WP_CLI::log( " User ID: {$session['user_id']}" ); - WP_CLI::log( " Started: " . ( $metadata['started_at'] ?? '-' ) ); - WP_CLI::log( " Messages: " . count( $messages ) ); + WP_CLI::log( ' Started: ' . ( $metadata['started_at'] ?? '-' ) ); + WP_CLI::log( ' Messages: ' . count( $messages ) ); if ( ! empty( $messages ) ) { WP_CLI::log( '' ); @@ -182,8 +182,8 @@ public function get( array $args, array $assoc_args ): void { $display_messages = array(); foreach ( $messages as $msg ) { - $role = $msg['role'] ?? 'unknown'; - $content = $msg['content'] ?? ''; + $role = $msg['role'] ?? 'unknown'; + $content = $msg['content'] ?? ''; $truncated = mb_strlen( $content ) > 100 ? mb_substr( $content, 0, 97 ) . '...' : $content; @@ -241,7 +241,7 @@ public function create( array $args, array $assoc_args ): void { 'source' => $source, ); - $chat_db = new ChatDatabase(); + $chat_db = new ChatDatabase(); $session_id = $chat_db->create_session( $user_id, $agent_id, $metadata, $context ); if ( empty( $session_id ) ) { @@ -378,6 +378,6 @@ private function get_user_id( array $assoc_args ): int { return (int) $assoc_args['user']; } - return get_current_user_id() ?: 1; + return get_current_user_id() ? get_current_user_id() : 1; } } diff --git a/inc/Cli/Commands/SystemCommand.php b/inc/Cli/Commands/SystemCommand.php index c9b5ba78..1b371259 100644 --- a/inc/Cli/Commands/SystemCommand.php +++ b/inc/Cli/Commands/SystemCommand.php @@ -240,7 +240,7 @@ public function run( array $args, array $assoc_args ): void { * @subcommand prompts */ public function prompts( array $args, array $assoc_args ): void { - $format = $assoc_args['format'] ?? 'table'; + $format = $assoc_args['format'] ?? 'table'; $handlers = TaskRegistry::getHandlers(); $overrides = SystemTask::getAllPromptOverrides(); @@ -354,7 +354,7 @@ public function prompt_get( array $args, array $assoc_args ): void { WP_CLI::log( sprintf( 'Override: %s', $has_override ? 'yes' : 'no (using default)' ) ); WP_CLI::log( sprintf( 'Variables: %s', implode( ', ', array_map( function ( $k, $v ) { - return "{{" . $k . "}} — " . $v; + return '{{' . $k . '}} — ' . $v; }, array_keys( $definition['variables'] ), array_values( $definition['variables'] ) diff --git a/inc/Core/Admin/FlowFormatter.php b/inc/Core/Admin/FlowFormatter.php index 86943017..1ac2bb24 100644 --- a/inc/Core/Admin/FlowFormatter.php +++ b/inc/Core/Admin/FlowFormatter.php @@ -55,7 +55,7 @@ public static function format_flow_for_response( array $flow, ?array $latest_job // Apply defaults to the primary handler config. if ( ! empty( $effective_slug ) ) { - $primary_config = $step_data['handler_configs'][ $effective_slug ] ?? array(); + $primary_config = $step_data['handler_configs'][ $effective_slug ] ?? array(); $step_data['handler_configs'][ $effective_slug ] = $handler_abilities->applyDefaults( $effective_slug, $primary_config diff --git a/inc/Core/Admin/Pages/Logs/LogsFilters.php b/inc/Core/Admin/Pages/Logs/LogsFilters.php index d7b0f04a..db038e9d 100644 --- a/inc/Core/Admin/Pages/Logs/LogsFilters.php +++ b/inc/Core/Admin/Pages/Logs/LogsFilters.php @@ -40,23 +40,23 @@ function ( $pages ) { 'position' => 30, 'templates' => __DIR__ . '/templates/', 'assets' => array( - 'css' => array( - 'wp-components' => array( - 'file' => null, // Use WordPress core version - 'deps' => array(), - 'media' => 'all', - ), - 'datamachine-tabs' => array( - 'file' => 'inc/Core/Admin/shared/styles/tabs.css', - 'deps' => array(), - 'media' => 'all', - ), - 'datamachine-logs-page' => array( - 'file' => 'inc/Core/Admin/Pages/Logs/assets/css/logs-page.css', - 'deps' => array(), - 'media' => 'all', + 'css' => array( + 'wp-components' => array( + 'file' => null, // Use WordPress core version + 'deps' => array(), + 'media' => 'all', + ), + 'datamachine-tabs' => array( + 'file' => 'inc/Core/Admin/shared/styles/tabs.css', + 'deps' => array(), + 'media' => 'all', + ), + 'datamachine-logs-page' => array( + 'file' => 'inc/Core/Admin/Pages/Logs/assets/css/logs-page.css', + 'deps' => array(), + 'media' => 'all', + ), ), - ), 'js' => array( 'datamachine-logs-react' => array( 'file' => 'inc/Core/Admin/assets/build/logs-react.js', diff --git a/inc/Core/Database/Agents/AgentAccess.php b/inc/Core/Database/Agents/AgentAccess.php index 6e039b73..1b330358 100644 --- a/inc/Core/Database/Agents/AgentAccess.php +++ b/inc/Core/Database/Agents/AgentAccess.php @@ -151,7 +151,7 @@ public function get_access( int $agent_id, int $user_id ): ?array { ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared - return $row ?: null; + return $row ? $row : null; } /** @@ -190,7 +190,7 @@ public function get_agent_ids_for_user( int $user_id, ?string $minimum_role = nu // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared } - return array_map( 'intval', $results ?: array() ); + return array_map( 'intval', $results ? $results : array() ); } /** @@ -211,7 +211,7 @@ public function get_users_for_agent( int $agent_id ): array { ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared - return $results ?: array(); + return $results ? $results : array(); } /** @@ -272,7 +272,11 @@ private function roles_at_or_above( string $role ): array { * @return bool */ private function role_meets_minimum( string $actual_role, string $minimum_role ): bool { - $hierarchy = array( 'viewer' => 0, 'operator' => 1, 'admin' => 2 ); + $hierarchy = array( + 'viewer' => 0, + 'operator' => 1, + 'admin' => 2, + ); $actual_level = $hierarchy[ $actual_role ] ?? -1; $minimum_level = $hierarchy[ $minimum_role ] ?? 0; diff --git a/inc/Core/Database/Agents/Agents.php b/inc/Core/Database/Agents/Agents.php index 9ccd79d4..c7902a12 100644 --- a/inc/Core/Database/Agents/Agents.php +++ b/inc/Core/Database/Agents/Agents.php @@ -234,7 +234,7 @@ public function get_all(): array { foreach ( $rows as &$row ) { if ( ! empty( $row['agent_config'] ) ) { - $decoded = json_decode( $row['agent_config'], true ); + $decoded = json_decode( $row['agent_config'], true ); $row['agent_config'] = is_array( $decoded ) ? $decoded : array(); } } diff --git a/inc/Core/Database/Chat/Chat.php b/inc/Core/Database/Chat/Chat.php index eea92793..0f4adba4 100644 --- a/inc/Core/Database/Chat/Chat.php +++ b/inc/Core/Database/Chat/Chat.php @@ -124,7 +124,7 @@ public static function ensure_context_column(): void { // Idempotent index normalization: drop legacy, add new — only when needed. // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared - $indexes = $wpdb->get_results( $wpdb->prepare( 'SHOW INDEX FROM %i', $table_name ) ); + $indexes = $wpdb->get_results( $wpdb->prepare( 'SHOW INDEX FROM %i', $table_name ) ); $existing_keys = array_unique( array_column( $indexes, 'Key_name' ) ); if ( in_array( 'agent_type', $existing_keys, true ) ) { @@ -227,9 +227,9 @@ public function create_session( 'error', 'Failed to create chat session', array( - 'user_id' => $user_id, - 'error' => $wpdb->last_error, - 'context' => $context, + 'user_id' => $user_id, + 'error' => $wpdb->last_error, + 'context' => $context, ) ); return ''; diff --git a/inc/Core/Database/Jobs/JobsOperations.php b/inc/Core/Database/Jobs/JobsOperations.php index bd6667d9..e97454a9 100644 --- a/inc/Core/Database/Jobs/JobsOperations.php +++ b/inc/Core/Database/Jobs/JobsOperations.php @@ -71,10 +71,10 @@ public function create_job( array $job_data ): int|false { $agent_id = isset( $job_data['agent_id'] ) ? absint( $job_data['agent_id'] ) : null; $data = array( - 'user_id' => $user_id, - 'source' => $source, - 'label' => $label, - 'status' => 'pending', + 'user_id' => $user_id, + 'source' => $source, + 'label' => $label, + 'status' => 'pending', ); $format = array( '%d', '%s', '%s', '%s' ); diff --git a/inc/Core/Database/Logs/LogRepository.php b/inc/Core/Database/Logs/LogRepository.php index 9d55ae01..8387886d 100644 --- a/inc/Core/Database/Logs/LogRepository.php +++ b/inc/Core/Database/Logs/LogRepository.php @@ -181,12 +181,14 @@ public function get_logs( array $filters = array() ): array { // Count total. // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared if ( ! empty( $params ) ) { + // phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- Dynamic query construction with safe values. $total = (int) $this->wpdb->get_var( $this->wpdb->prepare( "SELECT COUNT(*) FROM {$this->table_name} WHERE {$where_sql}", ...$params ) ); + // phpcs:enable WordPress.DB.PreparedSQLPlaceholders } else { $total = (int) $this->wpdb->get_var( "SELECT COUNT(*) FROM {$this->table_name} WHERE {$where_sql}" @@ -195,6 +197,7 @@ public function get_logs( array $filters = array() ): array { // Fetch items. $query_params = array_merge( $params, array( $per_page, $offset ) ); + // phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- Dynamic query construction with safe values. $items = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT * FROM {$this->table_name} WHERE {$where_sql} ORDER BY created_at DESC, id DESC LIMIT %d OFFSET %d", @@ -202,13 +205,14 @@ public function get_logs( array $filters = array() ): array { ), ARRAY_A ); + // phpcs:enable WordPress.DB.PreparedSQLPlaceholders // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared // Decode context JSON. if ( $items ) { foreach ( $items as &$item ) { if ( ! empty( $item['context'] ) ) { - $decoded = json_decode( $item['context'], true ); + $decoded = json_decode( $item['context'], true ); $item['context'] = is_array( $decoded ) ? $decoded : array(); } else { $item['context'] = array(); @@ -218,7 +222,7 @@ public function get_logs( array $filters = array() ): array { } return array( - 'items' => $items ?: array(), + 'items' => $items ? $items : array(), 'total' => $total, 'page' => $page, 'pages' => max( 1, (int) ceil( $total / $per_page ) ), @@ -233,12 +237,14 @@ public function get_logs( array $filters = array() ): array { */ public function prune_before( string $before_datetime ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared + // phpcs:disable WordPress.DB.PreparedSQL -- Table name from $wpdb->prefix, not user input. return $this->wpdb->query( $this->wpdb->prepare( "DELETE FROM {$this->table_name} WHERE created_at < %s", $before_datetime ) ); + // phpcs:enable WordPress.DB.PreparedSQL } /** @@ -263,7 +269,9 @@ public function clear_for_agent( int $agent_id ) { */ public function clear_all() { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared + // phpcs:disable WordPress.DB.PreparedSQL -- Table name from $wpdb->prefix, not user input. return $this->wpdb->query( "TRUNCATE TABLE {$this->table_name}" ); + // phpcs:enable WordPress.DB.PreparedSQL } /** @@ -287,6 +295,7 @@ public function get_metadata( ?int $agent_id = null ): array { // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared if ( ! empty( $params ) ) { + // phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- Dynamic query construction with safe values. $row = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT COUNT(*) AS total_entries, MIN(created_at) AS oldest, MAX(created_at) AS newest FROM {$this->table_name} WHERE {$where}", @@ -294,6 +303,7 @@ public function get_metadata( ?int $agent_id = null ): array { ), ARRAY_A ); + // phpcs:enable WordPress.DB.PreparedSQLPlaceholders } else { $row = $this->wpdb->get_row( "SELECT COUNT(*) AS total_entries, MIN(created_at) AS oldest, MAX(created_at) AS newest FROM {$this->table_name} WHERE {$where}", @@ -326,6 +336,7 @@ public function get_level_counts( ?int $agent_id = null ): array { // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared if ( ! empty( $params ) ) { + // phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- Dynamic query construction with safe values. $rows = $this->wpdb->get_results( $this->wpdb->prepare( "SELECT level, COUNT(*) AS cnt FROM {$this->table_name} WHERE {$where} GROUP BY level", @@ -333,6 +344,7 @@ public function get_level_counts( ?int $agent_id = null ): array { ), ARRAY_A ); + // phpcs:enable WordPress.DB.PreparedSQLPlaceholders } else { $rows = $this->wpdb->get_results( "SELECT level, COUNT(*) AS cnt FROM {$this->table_name} WHERE {$where} GROUP BY level", diff --git a/inc/Core/FilesRepository/DirectoryManager.php b/inc/Core/FilesRepository/DirectoryManager.php index 814bc2b7..8f9824c4 100644 --- a/inc/Core/FilesRepository/DirectoryManager.php +++ b/inc/Core/FilesRepository/DirectoryManager.php @@ -368,10 +368,10 @@ public function get_workspace_directory(): string { } // 2. System-level default (outside web root). - $system_path = '/var/lib/datamachine/workspace'; - $system_base = dirname( $system_path ); - $fs = FilesystemHelper::get(); - $base_writable = $fs + $system_path = '/var/lib/datamachine/workspace'; + $system_base = dirname( $system_path ); + $fs = FilesystemHelper::get(); + $base_writable = $fs ? $fs->is_writable( $system_base ) : is_writable( $system_base ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable $parent_writable = ! $base_writable && ! file_exists( $system_base ) && ( diff --git a/inc/Core/FilesRepository/MediaValidator.php b/inc/Core/FilesRepository/MediaValidator.php index 6dc615d7..5e21327b 100644 --- a/inc/Core/FilesRepository/MediaValidator.php +++ b/inc/Core/FilesRepository/MediaValidator.php @@ -145,7 +145,7 @@ public function validate_against_constraints( string $file_path, array $constrai // Max file size. if ( isset( $constraints['max_file_size'] ) ) { $pass = $file_size <= (int) $constraints['max_file_size']; - $result['results']['max_file_size'] = $pass; + $result['results']['max_file_size'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( @@ -160,7 +160,7 @@ public function validate_against_constraints( string $file_path, array $constrai // Allowed MIME types (override default list). if ( isset( $constraints['allowed_mimes'] ) && is_array( $constraints['allowed_mimes'] ) ) { $pass = in_array( $mime_type, $constraints['allowed_mimes'], true ); - $result['results']['allowed_mimes'] = $pass; + $result['results']['allowed_mimes'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( @@ -194,7 +194,7 @@ protected function validate_metadata_constraints( array &$result, array $constra // Duration constraints. if ( isset( $constraints['max_duration'] ) && isset( $metadata['duration'] ) ) { $pass = $metadata['duration'] <= (float) $constraints['max_duration']; - $result['results']['max_duration'] = $pass; + $result['results']['max_duration'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( @@ -208,7 +208,7 @@ protected function validate_metadata_constraints( array &$result, array $constra if ( isset( $constraints['min_duration'] ) && isset( $metadata['duration'] ) ) { $pass = $metadata['duration'] >= (float) $constraints['min_duration']; - $result['results']['min_duration'] = $pass; + $result['results']['min_duration'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( @@ -222,9 +222,9 @@ protected function validate_metadata_constraints( array &$result, array $constra // Codec constraint. if ( isset( $constraints['allowed_codecs'] ) && is_array( $constraints['allowed_codecs'] ) && isset( $metadata['codec'] ) ) { - $codec_lower = strtolower( $metadata['codec'] ); - $allowed_lower = array_map( 'strtolower', $constraints['allowed_codecs'] ); - $pass = in_array( $codec_lower, $allowed_lower, true ); + $codec_lower = strtolower( $metadata['codec'] ); + $allowed_lower = array_map( 'strtolower', $constraints['allowed_codecs'] ); + $pass = in_array( $codec_lower, $allowed_lower, true ); $result['results']['allowed_codecs'] = $pass; if ( ! $pass ) { $result['valid'] = false; @@ -257,7 +257,7 @@ private function validate_resolution_constraints( array &$result, array $constra if ( isset( $constraints['max_width'] ) ) { $pass = $width <= (int) $constraints['max_width']; - $result['results']['max_width'] = $pass; + $result['results']['max_width'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( '%s width (%dpx) exceeds maximum (%dpx)', $label, $width, (int) $constraints['max_width'] ); @@ -266,7 +266,7 @@ private function validate_resolution_constraints( array &$result, array $constra if ( isset( $constraints['max_height'] ) ) { $pass = $height <= (int) $constraints['max_height']; - $result['results']['max_height'] = $pass; + $result['results']['max_height'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( '%s height (%dpx) exceeds maximum (%dpx)', $label, $height, (int) $constraints['max_height'] ); @@ -275,7 +275,7 @@ private function validate_resolution_constraints( array &$result, array $constra if ( isset( $constraints['min_width'] ) ) { $pass = $width >= (int) $constraints['min_width']; - $result['results']['min_width'] = $pass; + $result['results']['min_width'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( '%s width (%dpx) below minimum (%dpx)', $label, $width, (int) $constraints['min_width'] ); @@ -284,7 +284,7 @@ private function validate_resolution_constraints( array &$result, array $constra if ( isset( $constraints['min_height'] ) ) { $pass = $height >= (int) $constraints['min_height']; - $result['results']['min_height'] = $pass; + $result['results']['min_height'] = $pass; if ( ! $pass ) { $result['valid'] = false; $result['errors'][] = sprintf( '%s height (%dpx) below minimum (%dpx)', $label, $height, (int) $constraints['min_height'] ); diff --git a/inc/Core/FilesRepository/VideoMetadata.php b/inc/Core/FilesRepository/VideoMetadata.php index 8f76eee3..c2687ab7 100644 --- a/inc/Core/FilesRepository/VideoMetadata.php +++ b/inc/Core/FilesRepository/VideoMetadata.php @@ -79,7 +79,7 @@ public static function extract( string $file_path ): array { if ( self::is_ffprobe_available() ) { $ffprobe_data = self::extract_via_ffprobe( $file_path ); if ( null !== $ffprobe_data ) { - $result = array_merge( $result, $ffprobe_data ); + $result = array_merge( $result, $ffprobe_data ); $result['ffprobe'] = true; return $result; } @@ -146,13 +146,13 @@ private static function extract_via_ffprobe( string $file_path ): ?array { $stream = $json['streams'][0] ?? array(); $result = array( - 'duration' => null, - 'width' => null, - 'height' => null, - 'codec' => null, - 'bitrate' => null, + 'duration' => null, + 'width' => null, + 'height' => null, + 'codec' => null, + 'bitrate' => null, 'framerate' => null, - 'format' => null, + 'format' => null, ); // Duration (from format, more reliable than stream). diff --git a/inc/Core/PluginSettings.php b/inc/Core/PluginSettings.php index 71dcad9f..2933d42d 100644 --- a/inc/Core/PluginSettings.php +++ b/inc/Core/PluginSettings.php @@ -22,7 +22,7 @@ class PluginSettings { public const DEFAULT_MAX_TURNS = 25; - private static ?array $cache = null; + private static ?array $cache = null; private static array $agent_model_cache = array(); /** @@ -172,7 +172,7 @@ public static function getContextModel( string $context ): array { * @return array{ provider: string, model: string } */ public static function resolveModelForAgentContext( ?int $agent_id, string $context ): array { - $agent_id = (int) $agent_id; + $agent_id = (int) $agent_id; $cache_key = $agent_id . ':' . $context; if ( isset( self::$agent_model_cache[ $cache_key ] ) ) { @@ -246,7 +246,7 @@ public static function getContexts(): array { * @return void */ public static function clearCache(): void { - self::$cache = null; + self::$cache = null; self::$agent_model_cache = array(); } diff --git a/inc/Core/Similarity/SimilarityEngine.php b/inc/Core/Similarity/SimilarityEngine.php index a474885f..8257735e 100644 --- a/inc/Core/Similarity/SimilarityEngine.php +++ b/inc/Core/Similarity/SimilarityEngine.php @@ -57,13 +57,64 @@ class SimilarityEngine { * @var array */ const STOP_WORDS = array( - 'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', - 'for', 'of', 'with', 'by', 'from', 'is', 'it', 'are', 'was', - 'were', 'be', 'been', 'being', 'have', 'has', 'had', 'do', 'does', - 'did', 'will', 'would', 'could', 'should', 'may', 'might', 'shall', - 'can', 'not', 'no', 'if', 'when', 'what', 'why', 'how', 'who', - 'where', 'which', 'that', 'this', 'you', 'your', 'my', 'am', - 'me', 'we', 'they', 'them', 'its', + 'the', + 'a', + 'an', + 'and', + 'or', + 'but', + 'in', + 'on', + 'at', + 'to', + 'for', + 'of', + 'with', + 'by', + 'from', + 'is', + 'it', + 'are', + 'was', + 'were', + 'be', + 'been', + 'being', + 'have', + 'has', + 'had', + 'do', + 'does', + 'did', + 'will', + 'would', + 'could', + 'should', + 'may', + 'might', + 'shall', + 'can', + 'not', + 'no', + 'if', + 'when', + 'what', + 'why', + 'how', + 'who', + 'where', + 'which', + 'that', + 'this', + 'you', + 'your', + 'my', + 'am', + 'me', + 'we', + 'they', + 'them', + 'its', ); // ----------------------------------------------------------------------- diff --git a/inc/Core/Similarity/SimilarityResult.php b/inc/Core/Similarity/SimilarityResult.php index a65abd2b..44ea013f 100644 --- a/inc/Core/Similarity/SimilarityResult.php +++ b/inc/Core/Similarity/SimilarityResult.php @@ -20,11 +20,11 @@ class SimilarityResult { /** * Strategy constants. */ - const STRATEGY_EXACT = 'exact'; - const STRATEGY_PREFIX = 'prefix'; - const STRATEGY_EDIT = 'levenshtein'; - const STRATEGY_JACCARD = 'jaccard'; - const STRATEGY_NONE = 'none'; + const STRATEGY_EXACT = 'exact'; + const STRATEGY_PREFIX = 'prefix'; + const STRATEGY_EDIT = 'levenshtein'; + const STRATEGY_JACCARD = 'jaccard'; + const STRATEGY_NONE = 'none'; /** * Whether the comparison matched. @@ -73,13 +73,13 @@ class SimilarityResult { * @param string $normalized_b Normalized second input. */ public function __construct( - bool $match, + bool $match_value, float $score, string $strategy, string $normalized_a = '', string $normalized_b = '' ) { - $this->match = $match; + $this->match = $match_value; $this->score = $score; $this->strategy = $strategy; $this->normalized_a = $normalized_a; diff --git a/inc/Core/Steps/AI/AIStep.php b/inc/Core/Steps/AI/AIStep.php index 33323aaf..d403330a 100644 --- a/inc/Core/Steps/AI/AIStep.php +++ b/inc/Core/Steps/AI/AIStep.php @@ -179,7 +179,7 @@ protected function executeStep(): array { $max_turns = PluginSettings::get( 'max_turns', PluginSettings::DEFAULT_MAX_TURNS ); // Resolve user_id and agent_id from engine snapshot (set by RunFlowAbility). - $user_id = (int) ( $job_snapshot['user_id'] ?? 0 ); + $user_id = (int) ( $job_snapshot['user_id'] ?? 0 ); $payload = array( 'job_id' => $this->job_id, diff --git a/inc/Core/Steps/SystemTask/SystemTaskStep.php b/inc/Core/Steps/SystemTask/SystemTaskStep.php index a94db3b9..fa83634f 100644 --- a/inc/Core/Steps/SystemTask/SystemTaskStep.php +++ b/inc/Core/Steps/SystemTask/SystemTaskStep.php @@ -150,7 +150,7 @@ protected function executeStep(): array { } // Resolve the task handler class. - $handlers = TaskRegistry::getHandlers(); + $handlers = TaskRegistry::getHandlers(); $handler_class = $handlers[ $task_type ]; // Create a child job for independent tracking. diff --git a/inc/Engine/AI/Directives/DailyMemorySelectorDirective.php b/inc/Engine/AI/Directives/DailyMemorySelectorDirective.php index 0702e701..6575ee7b 100644 --- a/inc/Engine/AI/Directives/DailyMemorySelectorDirective.php +++ b/inc/Engine/AI/Directives/DailyMemorySelectorDirective.php @@ -109,7 +109,7 @@ public static function get_outputs( string $provider_name, array $tools, ?string break; } - $outputs[] = array( + $outputs[] = array( 'type' => 'system_text', 'content' => "## Daily Memory: {$date}\n{$content}", ); @@ -254,8 +254,8 @@ private static function get_date_range( ?string $from, ?string $to, DailyMemory } // Get all available dates. - $all = $daily->list_all(); - $dates = array(); + $all = $daily->list_all(); + $dates = array(); foreach ( $all['months'] as $month_key => $days ) { list( $year, $month ) = explode( '/', $month_key ); diff --git a/inc/Engine/AI/System/Tasks/SystemTask.php b/inc/Engine/AI/System/Tasks/SystemTask.php index 9f7e5129..d3fd0ac8 100644 --- a/inc/Engine/AI/System/Tasks/SystemTask.php +++ b/inc/Engine/AI/System/Tasks/SystemTask.php @@ -649,10 +649,10 @@ protected function reschedule( int $jobId, int $delaySeconds = 10 ): void { 'debug', "System Agent task rescheduled for job {$jobId} (attempt {$attempts}/{$max_attempts})", array( - 'job_id' => $jobId, - 'task_type' => $this->getTaskType(), - 'context' => 'system', - 'attempts' => $attempts, + 'job_id' => $jobId, + 'task_type' => $this->getTaskType(), + 'context' => 'system', + 'attempts' => $attempts, 'max_attempts' => $max_attempts, 'delay_seconds' => $delaySeconds, ) diff --git a/inc/Engine/AI/Tools/BaseTool.php b/inc/Engine/AI/Tools/BaseTool.php index 27b3a706..37f145f5 100644 --- a/inc/Engine/AI/Tools/BaseTool.php +++ b/inc/Engine/AI/Tools/BaseTool.php @@ -54,7 +54,7 @@ function ( $tools ) use ( $toolName, $toolDefinition, $contexts ) { } else { // Array definition — merge contexts directly. $toolDefinition['contexts'] = $contexts; - $tools[ $toolName ] = $toolDefinition; + $tools[ $toolName ] = $toolDefinition; } return $tools; } diff --git a/inc/Engine/AI/Tools/ToolManager.php b/inc/Engine/AI/Tools/ToolManager.php index 5cb68248..acb6c586 100644 --- a/inc/Engine/AI/Tools/ToolManager.php +++ b/inc/Engine/AI/Tools/ToolManager.php @@ -125,7 +125,7 @@ private function resolveToolDefinition( string $tool_id, mixed $definition, stri ); } - // Handle unified registry wrapper: ['_callable' => callable, 'contexts' => [...]] + // Handle unified registry wrapper: ['_callable' becomes callable, 'contexts' becomes [...]] $contexts = array(); if ( is_array( $definition ) && isset( $definition['_callable'] ) ) { $contexts = $definition['contexts'] ?? array(); diff --git a/inc/Engine/AI/Tools/ToolPolicyResolver.php b/inc/Engine/AI/Tools/ToolPolicyResolver.php index 37885807..508da5b5 100644 --- a/inc/Engine/AI/Tools/ToolPolicyResolver.php +++ b/inc/Engine/AI/Tools/ToolPolicyResolver.php @@ -197,8 +197,8 @@ private function gatherPipelineTools( array $context ): array { private function gatherToolsForContext( string $context_type ): array { $available_tools = array(); - $all_tools = $this->tool_manager->get_all_tools(); - $context_tools = $this->filterByContext( $all_tools, $context_type ); + $all_tools = $this->tool_manager->get_all_tools(); + $context_tools = $this->filterByContext( $all_tools, $context_type ); foreach ( $context_tools as $tool_name => $tool_config ) { if ( ! is_array( $tool_config ) || empty( $tool_config ) ) { diff --git a/inc/Engine/Actions/ImportExport.php b/inc/Engine/Actions/ImportExport.php index 0d4f6893..5477faf6 100644 --- a/inc/Engine/Actions/ImportExport.php +++ b/inc/Engine/Actions/ImportExport.php @@ -11,8 +11,6 @@ namespace DataMachine\Engine\Actions; - - // Prevent direct access if ( ! defined( 'WPINC' ) ) { die; diff --git a/inc/migrations.php b/inc/migrations.php index a38a66b1..3aa1f15c 100644 --- a/inc/migrations.php +++ b/inc/migrations.php @@ -72,8 +72,8 @@ function datamachine_migrate_handler_keys_to_plural() { if ( isset( $step['handler_slugs'] ) && is_array( $step['handler_slugs'] ) ) { // Ensure handler_configs exists when handler_slugs does. if ( ! isset( $step['handler_configs'] ) || ! is_array( $step['handler_configs'] ) ) { - $primary = $step['handler_slugs'][0] ?? ''; - $config = $step['handler_config'] ?? array(); + $primary = $step['handler_slugs'][0] ?? ''; + $config = $step['handler_config'] ?? array(); $step['handler_configs'] = ! empty( $primary ) ? array( $primary => $config ) : array(); $changed = true; } @@ -776,7 +776,7 @@ function datamachine_backfill_agent_ids(): void { ); // Cache of user_id → agent_id to avoid repeated lookups. - $agent_map = array(); + $agent_map = array(); $backfilled = 0; foreach ( $tables as $table ) { @@ -824,7 +824,7 @@ function datamachine_backfill_agent_ids(): void { $access_repo->bootstrap_owner_access( (int) $agent['agent_id'], $user_id ); } else { // Try to create agent for this user. - $created_id = datamachine_resolve_or_create_agent_id( $user_id ); + $created_id = datamachine_resolve_or_create_agent_id( $user_id ); $agent_map[ $user_id ] = $created_id; if ( $created_id > 0 ) { diff --git a/tests/Unit/Abilities/MediaAbilitiesTest.php b/tests/Unit/Abilities/MediaAbilitiesTest.php index 42589549..375f185e 100644 --- a/tests/Unit/Abilities/MediaAbilitiesTest.php +++ b/tests/Unit/Abilities/MediaAbilitiesTest.php @@ -163,8 +163,9 @@ public function test_video_metadata_nonexistent_file(): void { * Test video-metadata returns structured data. */ public function test_video_metadata_returns_structure(): void { + global $wp_filesystem; $temp_file = tempnam( sys_get_temp_dir(), 'dm-video-test-' ); - file_put_contents( $temp_file, str_repeat( 'x', 100 ) ); + $wp_filesystem->put_contents( $temp_file, str_repeat( 'x', 100 ) ); $result = $this->abilities->executeVideoMetadata( array( 'path' => $temp_file, diff --git a/tests/Unit/FilesRepository/MediaValidatorTest.php b/tests/Unit/FilesRepository/MediaValidatorTest.php index c452870b..c167110a 100644 --- a/tests/Unit/FilesRepository/MediaValidatorTest.php +++ b/tests/Unit/FilesRepository/MediaValidatorTest.php @@ -92,12 +92,13 @@ public function test_result_structure_consistent(): void { * Skipped when running as root since root can read any file. */ public function test_unreadable_file_error(): void { + global $wp_filesystem; if ( function_exists( 'posix_getuid' ) && posix_getuid() === 0 ) { $this->markTestSkipped( 'Cannot test unreadable files when running as root.' ); } $temp_file = tempnam( sys_get_temp_dir(), 'dm-media-test-' ); - file_put_contents( $temp_file, 'test' ); + $wp_filesystem->put_contents( $temp_file, 'test' ); chmod( $temp_file, 0000 ); $image_result = ( new ImageValidator() )->validate_repository_file( $temp_file ); diff --git a/tests/Unit/FilesRepository/VideoMetadataTest.php b/tests/Unit/FilesRepository/VideoMetadataTest.php index 4de83cb9..90e915fb 100644 --- a/tests/Unit/FilesRepository/VideoMetadataTest.php +++ b/tests/Unit/FilesRepository/VideoMetadataTest.php @@ -30,8 +30,9 @@ public function test_extract_nonexistent_file(): void { } public function test_extract_returns_file_size_and_mime(): void { + global $wp_filesystem; $temp_file = tempnam( sys_get_temp_dir(), 'dm-video-test-' ); - file_put_contents( $temp_file, str_repeat( 'x', 500 ) ); + $wp_filesystem->put_contents( $temp_file, str_repeat( 'x', 500 ) ); $result = VideoMetadata::extract( $temp_file ); @@ -43,8 +44,9 @@ public function test_extract_returns_file_size_and_mime(): void { } public function test_extract_result_structure(): void { + global $wp_filesystem; $temp_file = tempnam( sys_get_temp_dir(), 'dm-video-test-' ); - file_put_contents( $temp_file, 'fake' ); + $wp_filesystem->put_contents( $temp_file, 'fake' ); $result = VideoMetadata::extract( $temp_file ); diff --git a/tests/Unit/FilesRepository/VideoValidatorTest.php b/tests/Unit/FilesRepository/VideoValidatorTest.php index dceba37a..20ea6260 100644 --- a/tests/Unit/FilesRepository/VideoValidatorTest.php +++ b/tests/Unit/FilesRepository/VideoValidatorTest.php @@ -33,8 +33,9 @@ public function tear_down(): void { * Create a minimal fake video file with given content. */ private function create_test_file( string $filename, string $content = 'fake video content' ): string { + global $wp_filesystem; $path = $this->temp_dir . '/' . $filename; - file_put_contents( $path, $content ); + $wp_filesystem->put_contents( $path, $content ); return $path; }