403Webshell
Server IP : 121.121.20.254  /  Your IP : 216.73.216.70
Web Server : Microsoft-IIS/10.0
System : Windows NT WEB-SERVER 10.0 build 20348 (Windows Server 2022) AMD64
User : IUSR ( 0)
PHP Version : 8.3.28
Disable Function : NONE
MySQL : ON  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  C:/inetpub/wwwroot/AIWEBSTATION/wp-content/plugins/novamira-pro/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : C:/inetpub/wwwroot/AIWEBSTATION/wp-content/plugins/novamira-pro/includes/memory-admin.php
<?php

// SPDX-FileCopyrightText: 2026 Ovation S.r.l. <dev@novamira.ai>
// SPDX-License-Identifier: AGPL-3.0-or-later

declare(strict_types=1);

namespace Novamira\Pro;

use WP_Error;
use WP_Post;

if (!defined('ABSPATH')) {
    exit();
}

/**
 * Admin page for browsing, creating, editing, and deleting memories stored in
 * the `novamira_memory` custom post type. Registered as a submenu under the
 * shared `novamira-connect` menu, alongside the Pro License and Context pages.
 *
 * Relies on constants and helpers from includes/abilities/memory/bootstrap.php
 * which is loaded together with this file when memory is enabled.
 */

function memory_page_slug(): string
{
    return 'novamira-pro-memory';
}

function memory_option_name(): string
{
    return license_option_name('memory_enabled');
}

/**
 * Whether the memory abilities are exposed to agents. Users toggle this from the
 * memory admin page. The admin page itself remains reachable either way, so the
 * user can turn the system back on after disabling it.
 */
function memory_is_enabled(): bool
{
    return filter_var(get_option(memory_option_name(), default_value: true), FILTER_VALIDATE_BOOLEAN);
}

/** @return list<string> */
function memory_types(): array
{
    return \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_TYPES;
}

function memory_type_label(string $type): string
{
    return match ($type) {
        'user' => __('User', domain: 'novamira-pro'),
        'feedback' => __('Feedback', domain: 'novamira-pro'),
        'project' => __('Project', domain: 'novamira-pro'),
        'reference' => __('Reference', domain: 'novamira-pro'),
        default => $type,
    };
}

/** @param array<string, scalar> $query */
function memory_page_url(array $query = []): string
{
    return add_query_arg(array_merge(['page' => memory_page_slug()], $query), admin_url('admin.php'));
}

function register_memory_menu(): void
{
    if (!defined('NOVAMIRA_VERSION') || !license_allows_abilities()) {
        return;
    }

    add_submenu_page(
        parent_slug: 'novamira-connect',
        page_title: __('Novamira Pro Memory', domain: 'novamira-pro'),
        menu_title: __('Memory', domain: 'novamira-pro'),
        capability: \novamira_manage_capability(),
        menu_slug: memory_page_slug(),
        callback: __NAMESPACE__ . '\\render_memory_page',
    );
}

/** @return list<array{id:int,name:string,description:string,type:string,content:string,updated_at:string}> */
function memory_fetch_all(): array
{
    $args = [
        'post_type' => \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_POST_TYPE,
        'post_status' => 'publish',
        'posts_per_page' => -1,
        'orderby' => 'title',
        'order' => 'ASC',
    ];

    /** @var list<WP_Post> $posts */
    $posts = get_posts($args);

    $memories = [];
    foreach ($posts as $post) {
        $memories[] = \Novamira\Pro\Abilities\Memory\memory_shape($post);
    }

    return $memories;
}

/** @return array{id:int,name:string,description:string,type:string,content:string,updated_at:string}|null */
function memory_fetch_one(int $id): ?array
{
    /** @var WP_Post|null $post */
    $post = get_post($id);
    if (!$post instanceof WP_Post || $post->post_type !== \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_POST_TYPE) {
        return null;
    }

    return \Novamira\Pro\Abilities\Memory\memory_shape($post);
}

function memory_post_string(string $key): string
{
    $raw = $_POST[$key] ?? '';
    if (!is_string($raw)) {
        return '';
    }

    return wp_unslash($raw);
}

/**
 * @return array{
 *     notice: array{type:string,message:string}|null,
 *     view: 'list'|'new'|'edit'|null,
 *     id: int,
 *     form_values: array{name:string,description:string,type:string,content:string}|null
 * }|null
 */
function memory_handle_post(): ?array
{
    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') {
        return null;
    }

    $action = memory_post_string('novamira_pro_memory_action');
    if (!in_array($action, ['save', 'delete', 'toggle'], strict: true)) {
        return null;
    }

    check_admin_referer('novamira_pro_memory');

    if (!\novamira_current_user_can_manage()) {
        wp_die(esc_html__('You are not allowed to manage memories.', domain: 'novamira-pro'));
    }

    if ($action === 'save') {
        return memory_handle_save();
    }

    if ($action === 'delete') {
        return memory_handle_delete();
    }

    return memory_handle_toggle();
}

/**
 * @return array{
 *     notice: array{type:string,message:string},
 *     view: 'list',
 *     id: int,
 *     form_values: null
 * }
 */
function memory_handle_toggle(): array
{
    $enable = memory_post_string('memory_enabled') === '1';
    // Store as string to avoid WordPress's update_option short-circuit when the
    // option doesn't yet exist: get_option returns false as the implicit old
    // value, and update_option(name, false) bails out before add_option runs.
    update_option(memory_option_name(), $enable ? '1' : '0');

    return [
        'notice' => [
            'type' => 'success',
            'message' => $enable
                ? __('Memory abilities enabled for agents.', domain: 'novamira-pro')
                : __('Memory abilities disabled for agents. Existing memories are kept.', domain: 'novamira-pro'),
        ],
        'view' => 'list',
        'id' => 0,
        'form_values' => null,
    ];
}

function memory_post_int(string $key): int
{
    $raw = $_POST[$key] ?? null;

    return is_scalar($raw) ? (int) $raw : 0;
}

/**
 * @param array{name:string,description:string,type:string,content:string} $values
 * @return int|WP_Error
 */
function memory_persist(int $id, array $values): int|WP_Error
{
    $postarr = [
        'post_type' => \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_POST_TYPE,
        'post_status' => 'publish',
        'post_title' => sanitize_text_field($values['name']),
        'post_excerpt' => sanitize_text_field($values['description']),
        'post_content' => wp_strip_all_tags($values['content']),
    ];

    if ($id <= 0) {
        $result = wp_insert_post($postarr, wp_error: true);
        return memory_finalize_persist($result, $values['type']);
    }

    /** @var WP_Post|null $existing */
    $existing = get_post($id);
    if (
        !$existing instanceof WP_Post
        || $existing->post_type !== \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_POST_TYPE
    ) {
        return new WP_Error('not_found', __('Memory not found.', domain: 'novamira-pro'));
    }
    $postarr['ID'] = $id;
    $result = wp_update_post($postarr, wp_error: true);

    return memory_finalize_persist($result, $values['type']);
}

/**
 * @param int|WP_Error $result
 * @return int|WP_Error
 */
function memory_finalize_persist(int|WP_Error $result, string $type): int|WP_Error
{
    if (is_wp_error($result)) {
        return $result;
    }

    update_post_meta($result, \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_META_TYPE, $type);

    return $result;
}

/**
 * @return array{
 *     notice: array{type:string,message:string},
 *     view: 'new'|'edit',
 *     id: int,
 *     form_values: array{name:string,description:string,type:string,content:string}|null
 * }
 */
function memory_handle_save(): array
{
    $id = memory_post_int('memory_id');
    $type = memory_post_string('memory_type');
    $values = [
        'name' => sanitize_text_field(memory_post_string('memory_name')),
        'description' => sanitize_text_field(memory_post_string('memory_description')),
        'type' => in_array($type, memory_types(), strict: true) ? $type : 'project',
        'content' => memory_post_string('memory_content'),
    ];

    if (
        $values['name'] === ''
        || $values['description'] === ''
        || $values['content'] === ''
        || !in_array($type, memory_types(), strict: true)
    ) {
        return [
            'notice' => [
                'type' => 'error',
                'message' => __('Please fill in all fields and pick a valid type.', domain: 'novamira-pro'),
            ],
            'view' => $id > 0 ? 'edit' : 'new',
            'id' => $id,
            'form_values' => $values,
        ];
    }

    $result = memory_persist($id, $values);

    if (is_wp_error($result)) {
        return [
            'notice' => ['type' => 'error', 'message' => $result->get_error_message()],
            'view' => $id > 0 ? 'edit' : 'new',
            'id' => $id,
            'form_values' => $values,
        ];
    }

    return [
        'notice' => [
            'type' => 'success',
            'message' => $id > 0
                ? __('Memory updated.', domain: 'novamira-pro')
                : __('Memory created.', domain: 'novamira-pro'),
        ],
        'view' => 'edit',
        'id' => $result,
        'form_values' => null,
    ];
}

/**
 * @return array{
 *     notice: array{type:string,message:string},
 *     view: 'list',
 *     id: int,
 *     form_values: null
 * }
 */
function memory_handle_delete(): array
{
    $id = memory_post_int('memory_id');

    if ($id <= 0) {
        return [
            'notice' => [
                'type' => 'error',
                'message' => __('Invalid memory id.', domain: 'novamira-pro'),
            ],
            'view' => 'list',
            'id' => 0,
            'form_values' => null,
        ];
    }

    /** @var WP_Post|null $post */
    $post = get_post($id);
    if (!$post instanceof WP_Post || $post->post_type !== \Novamira\Pro\Abilities\Memory\NOVAMIRA_MEMORY_POST_TYPE) {
        return [
            'notice' => [
                'type' => 'error',
                'message' => __('Memory not found.', domain: 'novamira-pro'),
            ],
            'view' => 'list',
            'id' => 0,
            'form_values' => null,
        ];
    }

    $result = wp_delete_post($id, force_delete: true);

    if ($result === false || $result === null) {
        return [
            'notice' => [
                'type' => 'error',
                'message' => __('Failed to delete memory.', domain: 'novamira-pro'),
            ],
            'view' => 'list',
            'id' => 0,
            'form_values' => null,
        ];
    }

    return [
        'notice' => [
            'type' => 'success',
            'message' => __('Memory deleted.', domain: 'novamira-pro'),
        ],
        'view' => 'list',
        'id' => 0,
        'form_values' => null,
    ];
}

function render_memory_page(): void
{
    if (!\novamira_current_user_can_manage() || !license_allows_abilities()) {
        return;
    }

    $context = memory_resolve_admin_context();

    if (function_exists('novamira_render_admin_header')) {
        novamira_render_admin_header();
    }

    render_memory_page_view($context);
}

/**
 * @return array{
 *     notice: array{type:string,message:string}|null,
 *     view: 'list'|'new'|'edit',
 *     id: int,
 *     form_values: array{name:string,description:string,type:string,content:string}|null
 * }
 */
function memory_resolve_admin_context(): array
{
    $context = memory_handle_post();
    $notice = $context['notice'] ?? null;
    $forced_view = $context['view'] ?? null;
    $forced_id = $context['id'] ?? 0;
    $form_values = $context['form_values'] ?? null;

    $view = $forced_view;
    $view_id = $forced_id;
    if ($view === null) {
        $url_action = is_string($_GET['action'] ?? null) ? $_GET['action'] : '';
        $view = match ($url_action) {
            'new' => 'new',
            'edit' => 'edit',
            default => 'list',
        };
        $view_id = (int) ($_GET['id'] ?? 0);
    }

    return [
        'notice' => $notice,
        'view' => $view,
        'id' => $view_id,
        'form_values' => $form_values,
    ];
}

/**
 * @param array{
 *     notice: array{type:string,message:string}|null,
 *     view: 'list'|'new'|'edit',
 *     id: int,
 *     form_values: array{name:string,description:string,type:string,content:string}|null
 * } $context
 */
function render_memory_page_view(array $context): void
{
    if ($context['view'] === 'new') {
        render_memory_page_edit_view(memory: null, form_values: $context['form_values'], notice: $context['notice']);
        return;
    }

    if ($context['view'] === 'edit') {
        $memory = memory_fetch_one($context['id']);
        if ($memory === null) {
            render_memory_page_list_view(memory_not_found_notice($context['notice']));
            return;
        }
        render_memory_page_edit_view(memory: $memory, form_values: $context['form_values'], notice: $context['notice']);
        return;
    }

    render_memory_page_list_view($context['notice']);
}

/**
 * @param array{type:string,message:string}|null $notice
 * @return array{type:string,message:string}
 */
function memory_not_found_notice(?array $notice): array
{
    return $notice ?? [
        'type' => 'error',
        'message' => __('Memory not found.', domain: 'novamira-pro'),
    ];
}

function memory_requested_type_filter(): ?string
{
    $requested_type = is_string($_GET['type'] ?? null) ? $_GET['type'] : '';
    if (in_array($requested_type, memory_types(), strict: true)) {
        return $requested_type;
    }

    return null;
}

/**
 * @param list<array{id:int,name:string,description:string,type:string,content:string,updated_at:string}> $memories
 * @return array<string, int>
 */
function memory_type_counts(array $memories): array
{
    $counts = ['__total' => count($memories)];
    foreach (memory_types() as $type) {
        $counts[$type] = 0;
    }

    foreach ($memories as $memory) {
        if (!array_key_exists($memory['type'], $counts)) {
            continue;
        }
        ++$counts[$memory['type']];
    }

    return $counts;
}

/**
 * @return array{
 *     type_filter: string|null,
 *     counts: array<string, int>,
 *     memories: list<array{id:int,name:string,description:string,type:string,content:string,updated_at:string}>,
 *     new_url: string,
 *     all_url: string
 * }
 */
function memory_list_view_data(): array
{
    $type_filter = memory_requested_type_filter();
    $all_memories = memory_fetch_all();
    $memories = $type_filter === null
        ? $all_memories
        : array_values(array_filter($all_memories, static fn(array $m): bool => $m['type'] === $type_filter));

    return [
        'type_filter' => $type_filter,
        'counts' => memory_type_counts($all_memories),
        'memories' => $memories,
        'new_url' => memory_page_url(['action' => 'new']),
        'all_url' => memory_page_url(),
    ];
}

/** @param array{type:string,message:string}|null $notice */
function render_memory_page_list_view(?array $notice): void
{ ?>
    <div class="wrap">
        <h1 class="wp-heading-inline"><?php esc_html_e('Memory', domain: 'novamira-pro'); ?></h1>
        <hr class="wp-header-end">

        <p class="description" style="margin-top:8px;max-width:800px;"><?php esc_html_e(
            'Persistent, database-backed memory shared with agents across conversations. Store user profile details, feedback rules, project context, and external references here.',
            domain: 'novamira-pro',
        ); ?></p>
        <?php render_memory_list_contents($notice); ?>
    </div>
    <?php }

/** @param array{type:string,message:string}|null $notice */
function render_memory_list_contents(?array $notice): void
{
    $data = memory_list_view_data();

    render_memory_notice($notice);
    render_memory_list_styles();
    render_memory_list_heading($data['new_url']);
    render_memory_toggle();
    render_memory_filters(type_filter: $data['type_filter'], counts: $data['counts'], all_url: $data['all_url']);

    if ($data['memories'] === []) {
        render_memory_empty_state($data['new_url']);
        return;
    }

    render_memory_table($data['memories']);
}

function render_memory_list_styles(): void
{ ?>
    <style>
        .novamira-pro-section-title { margin-top:24px; margin-bottom:4px; font-size:16px; }
        .novamira-pro-memory-status { display:flex; align-items:center; justify-content:space-between; gap:16px; flex-wrap:wrap; background:#fff; border:1px solid #dcdcde; border-radius:12px; padding:16px 20px; margin:12px 0; max-width:1100px; }
        .novamira-pro-memory-status .status-text { display:flex; align-items:center; gap:10px; }
        .novamira-pro-memory-status .status-pill { display:inline-flex; align-items:center; gap:6px; padding:4px 12px; border-radius:999px; font-weight:600; font-size:12px; }
        .novamira-pro-memory-status .status-pill.is-on { background:#edf7ed; color:#0a5c1b; }
        .novamira-pro-memory-status .status-pill.is-off { background:#fcf0f1; color:#8a2424; }
        .novamira-pro-memory-status .status-hint { color:#50575e; margin:0; }
        .novamira-pro-memory-heading { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
        .novamira-pro-memory-filters { margin:12px 0 16px; }
        .novamira-pro-memory-filters a { margin-right:8px; text-decoration:none; }
        .novamira-pro-memory-filters a.is-active { font-weight:600; }
        .novamira-pro-memory-table td { vertical-align:top; }
        .novamira-pro-memory-type { display:inline-block; padding:2px 10px; border-radius:999px; background:#f0f0f1; font-size:12px; font-weight:500; }
        .novamira-pro-memory-type.is-user { background:#e0f2fe; color:#075985; }
        .novamira-pro-memory-type.is-feedback { background:#fef3c7; color:#92400e; }
        .novamira-pro-memory-type.is-project { background:#ede9fe; color:#5b21b6; }
        .novamira-pro-memory-type.is-reference { background:#dcfce7; color:#166534; }
        .novamira-pro-memory-description { color:#50575e; margin-top:2px; }
        .novamira-pro-memory-row-actions { white-space:nowrap; }
        .novamira-pro-memory-row-actions .delete-form { display:inline; }
    </style>
    <?php }

function render_memory_list_heading(string $new_url): void
{ ?>
    <div class="novamira-pro-memory-heading">
        <h2 id="novamira-pro-memory-heading" class="novamira-pro-section-title"><?php esc_html_e(
            'Memory',
            domain: 'novamira-pro',
        ); ?></h2>
        <a href="<?php echo esc_url($new_url); ?>" class="page-title-action"><?php esc_html_e(
            'Add new',
            domain: 'novamira-pro',
        ); ?></a>
    </div>
    <p class="description" style="margin-top:4px;max-width:800px;"><?php esc_html_e(
        'Persistent, database-backed memory shared with agents via the Novamira memory abilities. Add user profile, feedback rules, project context, and external references here to carry them across conversations.',
        domain: 'novamira-pro',
    ); ?></p>
    <?php }

/**
 * @param array<string, int> $counts
 */
function render_memory_filters(?string $type_filter, array $counts, string $all_url): void
{ ?>
    <div class="novamira-pro-memory-filters">
        <a href="<?php echo esc_url($all_url); ?>" class="<?php echo
            esc_attr($type_filter === null ? 'is-active' : '')
        ; ?>"><?php esc_html_e('All', domain: 'novamira-pro'); ?> (<?php echo (int) $counts['__total']; ?>)</a>
        <?php foreach (memory_types() as $type) {
            $url = memory_page_url(['type' => $type]);
            ?>
            <a href="<?php echo esc_url($url); ?>" class="<?php echo
                esc_attr($type_filter === $type ? 'is-active' : '')
            ; ?>"><?php echo esc_html(memory_type_label($type)); ?> (<?php echo (int) $counts[$type]; ?>)</a>
        <?php
        } ?>
    </div>
    <?php }

function render_memory_empty_state(string $new_url): void
{ ?>
    <div style="background:#fff;border:1px solid #dcdcde;border-radius:12px;padding:24px;max-width:800px;">
        <p style="margin-top:0;"><?php esc_html_e(
            'No memories yet. Add one to start building persistent context for agents.',
            domain: 'novamira-pro',
        ); ?></p>
        <p style="margin-bottom:0;"><a href="<?php echo
            esc_url($new_url)
        ; ?>" class="button button-primary"><?php esc_html_e(
            'Add your first memory',
            domain: 'novamira-pro',
        ); ?></a></p>
    </div>
    <?php }

/**
 * @param list<array{id:int,name:string,description:string,type:string,content:string,updated_at:string}> $memories
 */
function render_memory_table(array $memories): void
{ ?>
    <table class="widefat striped novamira-pro-memory-table">
        <thead>
            <tr>
                <th scope="col"><?php esc_html_e('Name', domain: 'novamira-pro'); ?></th>
                <th scope="col" style="width:140px;"><?php esc_html_e('Type', domain: 'novamira-pro'); ?></th>
                <th scope="col" style="width:180px;"><?php esc_html_e('Updated', domain: 'novamira-pro'); ?></th>
                <th scope="col" style="width:160px;"><?php esc_html_e('Actions', domain: 'novamira-pro'); ?></th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($memories as $memory) {
                render_memory_table_row($memory);
            } ?>
        </tbody>
    </table>
    <?php }

/** @param array{id:int,name:string,description:string,type:string,content:string,updated_at:string} $memory */
function render_memory_table_row(array $memory): void
{
    $edit_url = memory_page_url(['action' => 'edit', 'id' => $memory['id']]);
    ?>
    <tr>
        <td>
            <strong><a href="<?php echo esc_url($edit_url); ?>"><?php echo esc_html($memory['name']); ?></a></strong>
            <?php if ($memory['description'] !== '') { ?>
                <div class="novamira-pro-memory-description"><?php echo esc_html($memory['description']); ?></div>
            <?php } ?>
        </td>
        <td><span class="novamira-pro-memory-type is-<?php echo esc_attr($memory['type']); ?>"><?php echo
            esc_html(memory_type_label($memory['type']))
        ; ?></span></td>
        <td><?php echo esc_html(memory_format_date($memory['updated_at'])); ?></td>
        <td class="novamira-pro-memory-row-actions">
            <a href="<?php echo esc_url($edit_url); ?>" class="button button-small"><?php esc_html_e(
                'Edit',
                domain: 'novamira-pro',
            ); ?></a>
            <form method="post" action="<?php echo
                esc_url(memory_page_url())
            ; ?>" class="delete-form" onsubmit="return confirm('<?php echo
                esc_attr__('Delete this memory? This cannot be undone.', domain: 'novamira-pro')
            ; ?>');">
                <?php wp_nonce_field('novamira_pro_memory'); ?>
                <input type="hidden" name="novamira_pro_memory_action" value="delete">
                <input type="hidden" name="memory_id" value="<?php echo esc_attr((string) $memory['id']); ?>">
                <button type="submit" class="button button-small button-link-delete"><?php esc_html_e(
                    'Delete',
                    domain: 'novamira-pro',
                ); ?></button>
            </form>
        </td>
    </tr>
    <?php
}

/**
 * @param array{id:int,name:string,description:string,type:string,content:string,updated_at:string}|null $memory
 * @param array{name:string,description:string,type:string,content:string}|null $form_values
 * @param array{type:string,message:string}|null $notice
 */
function render_memory_page_edit_view(?array $memory, ?array $form_values, ?array $notice): void
{
    $back_url = memory_page_url();

    ?>
    <div class="wrap">
        <h1 id="novamira-pro-memory-edit-heading" class="wp-heading-inline"><?php echo
            esc_html(memory_edit_title($memory))
        ; ?></h1>
        <a href="<?php echo esc_url($back_url); ?>" class="page-title-action"><?php esc_html_e(
            'Back to list',
            domain: 'novamira-pro',
        ); ?></a>
        <hr class="wp-header-end">
        <?php render_memory_notice($notice); ?>
        <?php render_memory_edit_form(memory: $memory, form_values: $form_values); ?>
    </div>
    <?php
}

/** @param array{id:int,name:string,description:string,type:string,content:string,updated_at:string}|null $memory */
function memory_edit_title(?array $memory): string
{
    return $memory === null ? __('Add new memory', domain: 'novamira-pro') : __('Edit memory', domain: 'novamira-pro');
}

function render_memory_edit_form_styles(): void
{ ?>
    <style>
        .novamira-pro-memory-form { max-width:860px; background:#fff; border:1px solid #dcdcde; border-radius:12px; padding:24px; box-shadow:0 1px 2px rgba(0,0,0,.04); }
        .novamira-pro-memory-form .form-table th { width:180px; }
        .novamira-pro-memory-form textarea { font-family:monospace; font-size:13px; }
        .novamira-pro-memory-form .help { color:#50575e; margin-top:4px; max-width:560px; }
        .novamira-pro-memory-form .actions { display:flex; justify-content:space-between; align-items:center; gap:12px; margin-top:16px; flex-wrap:wrap; }
        .novamira-pro-memory-form .actions-primary { display:flex; gap:8px; align-items:center; }
    </style>
    <?php }

/**
 * @param array{id:int,name:string,description:string,type:string,content:string,updated_at:string}|null $memory
 * @param array{name:string,description:string,type:string,content:string}|null $form_values
 */
function render_memory_edit_form(?array $memory, ?array $form_values): void
{
    $is_edit = $memory !== null;
    $form_url = memory_page_url();
    $name = $form_values['name'] ?? $memory['name'] ?? '';
    $description = $form_values['description'] ?? $memory['description'] ?? '';
    $type = $form_values['type'] ?? $memory['type'] ?? 'project';
    $content = $form_values['content'] ?? $memory['content'] ?? '';

    render_memory_edit_form_styles();
    ?>

    <form method="post" action="<?php echo esc_url($form_url); ?>" class="novamira-pro-memory-form">
        <?php wp_nonce_field('novamira_pro_memory'); ?>
        <?php if ($is_edit) { ?>
            <input type="hidden" name="memory_id" value="<?php echo esc_attr((string) $memory['id']); ?>">
        <?php } ?>

        <table class="form-table" role="presentation">
            <tr>
                <th scope="row"><label for="memory_name"><?php esc_html_e(
                    'Name',
                    domain: 'novamira-pro',
                ); ?></label></th>
                <td>
                    <input type="text" id="memory_name" name="memory_name" class="regular-text" required value="<?php echo
                        esc_attr($name)
                    ; ?>">
                    <p class="help"><?php esc_html_e(
                        'Short title for this memory (e.g. "User profile", "No Bricks-specific framing").',
                        domain: 'novamira-pro',
                    ); ?></p>
                </td>
            </tr>
            <tr>
                <th scope="row"><label for="memory_type"><?php esc_html_e(
                    'Type',
                    domain: 'novamira-pro',
                ); ?></label></th>
                <td>
                    <select id="memory_type" name="memory_type" required>
                        <?php foreach (memory_types() as $t) { ?>
                            <option value="<?php echo esc_attr($t); ?>" <?php selected($type, $t); ?>><?php echo
                                esc_html(memory_type_label($t))
                            ; ?></option>
                        <?php } ?>
                    </select>
                    <p class="help"><?php esc_html_e(
                        'user: who the user is — role, preferences. feedback: how to approach work (with Why/How to apply lines). project: ongoing work & decisions. reference: pointers to external systems.',
                        domain: 'novamira-pro',
                    ); ?></p>
                </td>
            </tr>
            <tr>
                <th scope="row"><label for="memory_description"><?php esc_html_e(
                    'Description',
                    domain: 'novamira-pro',
                ); ?></label></th>
                <td>
                    <input type="text" id="memory_description" name="memory_description" class="large-text" required value="<?php echo
                        esc_attr($description)
                    ; ?>">
                    <p class="help"><?php esc_html_e(
                        'One-line hook used in the index to decide relevance — be specific.',
                        domain: 'novamira-pro',
                    ); ?></p>
                </td>
            </tr>
            <tr>
                <th scope="row"><label for="memory_content"><?php esc_html_e(
                    'Content',
                    domain: 'novamira-pro',
                ); ?></label></th>
                <td>
                    <textarea
                        id="memory_content"
                        name="memory_content"
                        rows="14"
                        class="large-text code"
                        required
                    ><?php echo esc_textarea($content); ?></textarea>
                    <p class="help"><?php esc_html_e(
                        'The memory body. For feedback/project types, structure as: rule/fact, then **Why:** and **How to apply:** lines.',
                        domain: 'novamira-pro',
                    ); ?></p>
                </td>
            </tr>
            <?php if ($is_edit) { ?>
                <tr>
                    <th scope="row"><?php esc_html_e('Last updated', domain: 'novamira-pro'); ?></th>
                    <td><?php echo esc_html(memory_format_date($memory['updated_at'])); ?></td>
                </tr>
            <?php } ?>
        </table>

        <div class="actions">
            <div class="actions-primary">
                <button type="submit" name="novamira_pro_memory_action" value="save" class="button button-primary"><?php echo
                    $is_edit
                        ? esc_html__('Save changes', domain: 'novamira-pro')
                        : esc_html__('Create memory', domain: 'novamira-pro')
                ; ?></button>
                <a href="<?php echo esc_url(memory_page_url()); ?>" class="button"><?php esc_html_e(
                    'Cancel',
                    domain: 'novamira-pro',
                ); ?></a>
            </div>
            <?php if ($is_edit) { ?>
                <button
                    type="submit"
                    name="novamira_pro_memory_action"
                    value="delete"
                    class="button button-link-delete"
                    onclick="return confirm('<?php echo
                        esc_attr__('Delete this memory? This cannot be undone.', domain: 'novamira-pro')
                    ; ?>');"
                ><?php esc_html_e('Delete', domain: 'novamira-pro'); ?></button>
            <?php } ?>
        </div>
    </form>
    <?php
}

function render_memory_toggle(): void
{
    $is_enabled = memory_is_enabled();
    $submit_value = $is_enabled ? '0' : '1';
    $submit_label = $is_enabled
        ? __('Disable memory abilities', domain: 'novamira-pro')
        : __('Enable memory abilities', domain: 'novamira-pro');
    $submit_class = $is_enabled ? 'button button-secondary' : 'button button-primary';
    $status_class = $is_enabled ? 'is-on' : 'is-off';
    $status_label = $is_enabled ? __('On', domain: 'novamira-pro') : __('Off', domain: 'novamira-pro');
    $hint = $is_enabled
        ? __('Agents can list, read, write, and delete memories via the memory abilities.', domain: 'novamira-pro')
        : __(
            'Memory abilities are hidden from agents. Existing memories stay in place and appear again when you re-enable.',
            domain: 'novamira-pro',
        );
    ?>
    <div class="novamira-pro-memory-status">
        <div>
            <div class="status-text">
                <strong><?php esc_html_e('Memory abilities:', domain: 'novamira-pro'); ?></strong>
                <span class="status-pill <?php echo esc_attr($status_class); ?>"><?php

                echo esc_html($status_label); ?></span>
            </div>
            <p class="status-hint" style="margin:6px 0 0;max-width:680px;"><?php echo esc_html($hint); ?></p>
        </div>
        <form method="post" action="<?php echo esc_url(memory_page_url()); ?>">
            <?php wp_nonce_field('novamira_pro_memory'); ?>
            <input type="hidden" name="novamira_pro_memory_action" value="toggle">
            <input type="hidden" name="memory_enabled" value="<?php echo esc_attr($submit_value); ?>">
            <button type="submit" class="<?php echo esc_attr($submit_class); ?>"><?php echo
                esc_html($submit_label)
            ; ?></button>
        </form>
    </div>
    <?php
}

/** @param array{type:string,message:string}|null $notice */
function render_memory_notice(?array $notice): void
{
    if ($notice === null) {
        return;
    }

    $type = in_array($notice['type'], ['success', 'warning', 'error', 'info'], strict: true) ? $notice['type'] : 'info';
    ?>
    <div class="notice notice-<?php echo esc_attr($type); ?> is-dismissible"><p><?php echo
        esc_html($notice['message'])
    ; ?></p></div>
    <?php
}

function memory_format_date(string $gmt): string
{
    if ($gmt === '' || $gmt === '0000-00-00 00:00:00') {
        return '—';
    }

    $timestamp = strtotime($gmt . ' UTC');
    if ($timestamp === false) {
        return $gmt;
    }

    $format = (string) get_option('date_format') . ' ' . (string) get_option('time_format');
    $formatted = wp_date($format, $timestamp);

    return $formatted === false ? $gmt : $formatted;
}

function boot_memory_admin(): void
{
    add_action('admin_menu', callback: __NAMESPACE__ . '\\register_memory_menu', priority: 45);
}

Youez - 2016 - github.com/yon3zu
LinuXploit