'object', 'properties' => $props]; if ($required) $schema['required'] = $required; return ['name' => $name, 'description' => $desc, 'scope' => $scope, 'handler' => 'AskTamMCP\\Extensions\\Batch10::' . $method, 'inputSchema' => $schema]; }; $registry->register($def('memory_set', 'Store a string value under a key. Optional ttl_minutes makes it expire (otherwise it persists). For structured data, pass JSON text as value.', ['key' => ['type' => 'string'], 'value' => ['type' => 'string'], 'ttl_minutes' => ['type' => 'integer', 'default' => 0]], ['key', 'value'], 'write', 'setVal')); $registry->register($def('memory_get', 'Retrieve a stored value by key.', ['key' => ['type' => 'string']], ['key'], 'read', 'getVal')); $registry->register($def('memory_list', 'List stored memory keys, optionally filtered by prefix.', ['prefix' => ['type' => 'string']], [], 'read', 'listKeys')); $registry->register($def('memory_delete', 'Delete a stored value by key.', ['key' => ['type' => 'string']], ['key'], 'write', 'deleteVal')); $registry->register($def('memory_append', 'Append an item to a newline-delimited list stored at key (created if absent).', ['key' => ['type' => 'string'], 'item' => ['type' => 'string']], ['key', 'item'], 'write', 'appendVal')); } private static function key(string $raw): string { $k = preg_replace('/[^a-z0-9_\-]/i', '', $raw); if ($k === '') throw new \RuntimeException('Invalid key.'); return self::PREFIX . $k; } public static function setVal(array $args): array { $opt = self::key((string) ($args['key'] ?? '')); $val = (string) ($args['value'] ?? ''); $ttl = (int) ($args['ttl_minutes'] ?? 0); if ($ttl > 0) { set_transient($opt, $val, $ttl * MINUTE_IN_SECONDS); delete_option($opt); } else { update_option($opt, $val, false); delete_transient($opt); } return ['key' => $args['key'], 'stored' => true, 'expires' => $ttl > 0 ? $ttl . 'm' : 'never']; } public static function getVal(array $args): array { $opt = self::key((string) ($args['key'] ?? '')); $v = get_option($opt, null); $source = 'option'; if ($v === null) { $t = get_transient($opt); if ($t === false) { $v = null; $source = null; } else { $v = $t; $source = 'transient'; } } return ['key' => $args['key'], 'value' => $v, 'exists' => $v !== null, 'source' => $source]; } public static function listKeys(array $args): array { global $wpdb; $prefix = isset($args['prefix']) ? (string) $args['prefix'] : ''; $like1 = self::PREFIX . '%'; $like2 = '_transient_' . self::PREFIX . '%'; $names = $wpdb->get_col($wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s", $like1, $like2 )); $keys = []; foreach ((array) $names as $n) { $k = str_replace(['_transient_timeout_', '_transient_', self::PREFIX], '', $n); if ($k === '' || strpos($n, '_transient_timeout_') === 0) continue; if ($prefix !== '' && strpos($k, $prefix) !== 0) continue; $keys[$k] = true; } $out = array_keys($keys); return ['count' => count($out), 'keys' => $out]; } public static function deleteVal(array $args): array { $opt = self::key((string) ($args['key'] ?? '')); $a = delete_option($opt); $b = delete_transient($opt); return ['key' => $args['key'], 'deleted' => ($a || $b)]; } public static function appendVal(array $args): array { $opt = self::key((string) ($args['key'] ?? '')); $item = (string) ($args['item'] ?? ''); $cur = get_option($opt, ''); if (!is_string($cur)) $cur = ''; $list = $cur === '' ? [] : explode("\n", $cur); $list[] = $item; update_option($opt, implode("\n", $list), false); return ['key' => $args['key'], 'count' => count($list)]; } }