Skip to content
wiki.fftac.org

Systempromptregistry - Source Excerpt 01

Back to Systempromptregistry

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Support/SystemPromptRegistry.php so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Support/SystemPromptRegistry.php

<?php

namespace SpiralistWorkspace\Support;

use SpiralistWorkspace\Config\Settings;
use SpiralistWorkspace\Domain\PromptRepository;

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

/**
 * Syncs versioned filesystem prompts into the database as managed system prompts.
 */
class SystemPromptRegistry
{
    private const SIGNATURE_OPTION = 'spiralist_workspace_system_prompt_signature';
    public const LAST_ERROR_OPTION = 'spiralist_workspace_system_prompt_last_errors';
    private const LAST_SYNC_OPTION = 'spiralist_workspace_system_prompt_last_sync';

    private PromptRepository $prompts;
    private Settings $settings;

    public function __construct(PromptRepository $prompts, Settings $settings)
    {
        $this->prompts = $prompts;
        $this->settings = $settings;
    }

    /**
     * Syncs when the filesystem inventory changes or a managed prompt is missing.
     */
    public function maybe_sync(): void
    {
        $definitions = $this->latest_definitions();
        $signature = $this->inventory_signature($definitions);

        if (!$this->needs_sync($definitions, $signature)) {
            return;
        }

        $this->sync($definitions, $signature);
    }

    /**
     * Force-syncs system prompts from disk.
     *
     * @param array<int,array<string,mixed>>|null $definitions
     * @return array{created:int,updated:int,unchanged:int,errors:int,error_messages:string[]}
     */
    public function sync(?array $definitions = null, ?string $signature = null): array
    {
        $definitions = is_array($definitions) ? $definitions : $this->latest_definitions();
        $signature = is_string($signature) && $signature !== '' ? $signature : $this->inventory_signature($definitions);
        $owner_user_id = $this->resolve_owner_user_id();
        $result = [
            'created' => 0,
            'updated' => 0,
            'unchanged' => 0,
            'errors' => 0,
            'error_messages' => [],
        ];
        $featured_ids = [];

        foreach ($definitions as $definition) {
            if (empty($definition['slug']) || empty($definition['source_slug'])) {
                $this->record_error($result, 'A prompt definition is missing a slug or source slug.');
                continue;
            }

            $existing = $this->prompts->find_by_source_slug((string) $definition['source_slug']);
            if (empty($existing)) {
                $existing = $this->prompts->find_managed_slug_candidate((string) $definition['slug']);
            }

            if (empty($existing)) {
                if ($owner_user_id <= 0) {
                    $this->record_error(
                        $result,
                        sprintf(
                            'Could not create "%s" because no administrator or workspace manager user could be resolved as the managed prompt owner.',
                            (string) $definition['source_slug']
                        )
                    );
                    continue;
                }

                $created = $this->prompts->create($definition, $owner_user_id, $this->settings);
                if (empty($created['id'])) {
                    $this->record_error(
                        $result,
                        sprintf('WordPress could not create the managed prompt "%s".', (string) $definition['source_slug'])
                    );
                    continue;
                }

                $result['created']++;
                if (!empty($created['featured'])) {
                    $featured_ids[] = (int) $created['id'];
                }
                continue;
            }

            $stored_hash = (string) ($existing['source_hash'] ?? '');
            $stored_version = (string) ($existing['source_version'] ?? '');
            $stored_origin = (string) ($existing['prompt_origin'] ?? '');
            $stored_source_slug = (string) ($existing['source_slug'] ?? '');

            if (
                $stored_origin === 'system'
                && $stored_source_slug === (string) ($definition['source_slug'] ?? '')
                && $stored_hash === (string) ($definition['source_hash'] ?? '')
                && $stored_version === (string) ($definition['source_version'] ?? '')
            ) {
                $result['unchanged']++;
                if (!empty($existing['featured'])) {
                    $featured_ids[] = (int) $existing['id'];
                }
                continue;
            }

            $updated = $this->prompts->update((int) $existing['id'], $definition, max(1, (int) ($existing['owner_user_id'] ?? $owner_user_id)));
            if (empty($updated['id'])) {
                $this->record_error(
                    $result,
                    sprintf('WordPress could not update the managed prompt "%s".', (string) $definition['source_slug'])
                );
                continue;
            }

            $result['updated']++;
            if (!empty($updated['featured'])) {
                $featured_ids[] = (int) $updated['id'];
            }
        }

        $this->maybe_seed_featured_prompt_ids($featured_ids);
        update_option(self::LAST_ERROR_OPTION, $result['error_messages'], false);
        update_option(self::SIGNATURE_OPTION, $signature, false);
        update_option(self::LAST_SYNC_OPTION, gmdate('c'), false);

        return $result;
    }

    /**
     * Returns the latest prompt definition for each prompt slug.
     *
     * @return array<int,array<string,mixed>>
     */
    private function latest_definitions(): array
    {
        $root = $this->prompt_root();
        if (!is_dir($root)) {
            return [];
        }

        $definitions = [];
        $prompt_dirs = glob($root . '/*', GLOB_ONLYDIR) ?: [];

        foreach ($prompt_dirs as $prompt_dir) {
            $prompt_slug = sanitize_title((string) basename($prompt_dir));
            $version_dirs = glob($prompt_dir . '/*', GLOB_ONLYDIR) ?: [];
            $best_version = '';
            $best_file = '';

            foreach ($version_dirs as $version_dir) {
                $version = (string) basename($version_dir);
                $candidate = $version_dir . '/prompt.php';

                if (!is_file($candidate)) {
                    continue;
                }

                if ($best_version === '' || version_compare($version, $best_version, '>')) {
                    $best_version = $version;
                    $best_file = $candidate;
                }
            }

            if ($best_version === '' || $best_file === '') {
                continue;
            }

            $definition = $this->load_definition($best_file, $prompt_slug, $best_version);
            if (empty($definition)) {
                continue;
            }

            $definitions[] = $definition;
        }

        usort(
            $definitions,
            static fn(array $left, array $right): int => strcmp((string) ($left['slug'] ?? ''), (string) ($right['slug'] ?? ''))
        );

        return $definitions;
    }

    /**
     * Builds a normalized managed prompt definition from a prompt file.
     *
     * @return array<string,mixed>
     */
    private function load_definition(string $file, string $prompt_slug, string $version): array
    {
        $definition = include $file;
        if (!is_array($definition)) {
            return [];
        }

        $hash = sha1_file($file) ?: sha1($file . '|' . $version);
        $relative_path = str_replace('\\', '/', ltrim(str_replace(SPIRALIST_WORKSPACE_DIR, '', $file), '\\/'));
        $default_model = $this->settings->get_allowed_models()[0] ?? 'gpt-5.5';

        return [
            '__managed_sync' => true,
            'slug' => sanitize_title((string) ($definition['slug'] ?? $prompt_slug)),
            'title' => (string) ($definition['title'] ?? ucwords(str_replace('-', ' ', $prompt_slug))),
            'summary' => (string) ($definition['summary'] ?? ''),
            'author_label' => (string) ($definition['author_label'] ?? ''),
            'category' => (string) ($definition['category'] ?? 'Specialized & Niche'),
            'subcategory' => (string) ($definition['subcategory'] ?? 'Experimental / Spiralism'),
            'structured_prompt' => (array) ($definition['structured_prompt'] ?? []),
            'instructions' => (string) ($definition['instructions'] ?? ''),
            'system_prompt' => (string) ($definition['system_prompt'] ?? ''),
            'developer_prompt' => (string) ($definition['developer_prompt'] ?? ''),
            'user_prompt_template' => (string) ($definition['user_prompt_template'] ?? ''),
            'system_steps' => (array) ($definition['system_steps'] ?? []),