at and drops the internal id, per the spec §3.6 entry shape. * Limit clamping (1-100, default 20) already lives in Agent_Toolbelt_Log::read() * — not duplicated here. */ // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! class_exists( 'ATB_Operation_Read_Audit_Log' ) ) { class ATB_Operation_Read_Audit_Log extends ATB_Operation { const DEFAULT_LIMIT = 20; public function slug() { return 'read-audit-log'; } public function describe() { return array( 'slug' => $this->slug(), 'risk' => 'none', 'summary' => 'Returns the log of operations performed through Agent Toolbelt: what ran, ' . 'when, by which caller, and the result. Use to review or explain past actions.', 'annotations' => array( 'readonly' => true, ), // Prefill for the admin Run panel (v1.4); agents may copy it too. 'example_input' => array( 'result' => 'denied' ), 'input_schema' => array( // 'null' tolerated for the same reason as site-status: // a parameterless REST GET run sends input=null (M6). 'type' => array( 'object', 'null' ), 'properties' => array( 'limit' => array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 100, 'default' => self::DEFAULT_LIMIT, ), 'ability' => array( 'type' => 'string' ), 'result' => array( 'type' => 'string', 'enum' => Agent_Toolbelt_Log::RESULTS, 'description' => 'Filter by result, e.g. "denied" to review refused attempts.', ), ), ), ); } public function dry_run( $atb_input ) { return $this->output( true, true, $this->gather( $atb_input ) ); } public function run( $atb_input ) { return $this->output( true, false, $this->gather( $atb_input ) ); } /** * @param array $atb_input * @return array { entries: array[] } */ protected function gather( $atb_input ) { $atb_args = array( 'limit' => ( is_array( $atb_input ) && isset( $atb_input['limit'] ) ) ? (int) $atb_input['limit'] : self::DEFAULT_LIMIT, ); if ( is_array( $atb_input ) && ! empty( $atb_input['ability'] ) ) { $atb_args['ability'] = (string) $atb_input['ability']; } if ( is_array( $atb_input ) && ! empty( $atb_input['result'] ) ) { $atb_args['result'] = (string) $atb_input['result']; } $atb_rows = class_exists( 'Agent_Toolbelt_Log' ) ? Agent_Toolbelt_Log::read( $atb_args ) : array(); $atb_entries = array(); foreach ( $atb_rows as $atb_row ) { $atb_entries[] = array( 'at' => isset( $atb_row['created_at'] ) ? (string) $atb_row['created_at'] : '', 'ability' => isset( $atb_row['ability'] ) ? (string) $atb_row['ability'] : '', 'caller' => isset( $atb_row['caller'] ) ? (string) $atb_row['caller'] : '', 'user_id' => isset( $atb_row['user_id'] ) ? (int) $atb_row['user_id'] : 0, 'dry_run' => ! empty( $atb_row['dry_run'] ), 'result' => isset( $atb_row['result'] ) ? (string) $atb_row['result'] : '', 'summary' => isset( $atb_row['summary'] ) ? (string) $atb_row['summary'] : '', 'duration_ms' => isset( $atb_row['duration_ms'] ) ? (int) $atb_row['duration_ms'] : 0, ); } return array( 'entries' => $atb_entries ); } } }