import { writable, derived, get } from 'svelte/store'; import type { MudProfile } from '$lib/profiles/ProfileManager'; import type { MudConnection } from '$lib/connection/MudConnection'; import type { Trigger } from '$lib/triggers/TriggerSystem'; // Store for active connections export const connections = writable<{ [key: string]: MudConnection }>({}); // Store for profiles export const profiles = writable([]); // Store for active profile ID export const activeProfileId = writable(null); // Store for triggers export const triggers = writable([]); // Store for MUD output history export const outputHistory = writable<{ id: string; text: string; timestamp: number; isInput?: boolean; highlights?: { pattern: string; color: string; isRegex: boolean }[] }[]>([]); // Store for connection status export const connectionStatus = writable<{ [key: string]: 'connected' | 'disconnected' | 'connecting' | 'error' }>({}); // Store for accessibility settings export const accessibilitySettings = writable({ textToSpeech: false, highContrast: false, fontSize: 16, lineSpacing: 1.2, speechRate: 1, speechPitch: 1, speechVolume: 1, interruptSpeechOnEnter: true // New setting for interrupting speech on Enter key }); // Store for UI settings export const uiSettings = writable({ isDarkMode: true, showTimestamps: true, showSidebar: true, splitViewDirection: 'horizontal', // or 'vertical' inputHistorySize: 100, outputBufferSize: 1000, ansiColor: true, font: 'monospace', debugGmcp: false, // Setting for GMCP debugging globalVolume: 0.7 // Global volume control for sounds (0-1) }); // Store for input history export const inputHistory = writable([]); export const inputHistoryIndex = writable(-1); // Derived store for active profile export const activeProfile = derived( [profiles, activeProfileId], ([$profiles, $activeProfileId]) => { if (!$activeProfileId) return null; return $profiles.find(profile => profile.id === $activeProfileId) || null; } ); // Derived store for active connection export const activeConnection = derived( [connections, activeProfileId], ([$connections, $activeProfileId]) => { if (!$activeProfileId) return null; return $connections[$activeProfileId] || null; } ); // Store for GMCP data export const gmcpData = writable<{ [module: string]: any }>({}); // Store for GMCP debug messages export const gmcpDebugLog = writable<{ id: string; module: string; data: any; timestamp: number }[]>([]); // Helper functions export function addToOutputHistory(text: string, isInput = false, highlights: { pattern: string; color: string; isRegex: boolean }[] = []) { outputHistory.update(history => { const maxSize = get(uiSettings).outputBufferSize; const newItem = { id: `output-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, text, timestamp: Date.now(), isInput, highlights }; // Limit history size const updatedHistory = [...history, newItem]; if (updatedHistory.length > maxSize) { return updatedHistory.slice(updatedHistory.length - maxSize); } return updatedHistory; }); } /** * Add GMCP message to debug log and possibly to output history if enabled */ export function logGmcpMessage(module: string, data: any) { console.log('logGmcpMessage called for module:', module); // Always add to debug log gmcpDebugLog.update(log => { const maxSize = 100; // Keep last 100 GMCP messages const newItem = { id: `gmcp-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`, module, data, timestamp: Date.now() }; const updatedLog = [...log, newItem]; if (updatedLog.length > maxSize) { return updatedLog.slice(updatedLog.length - maxSize); } return updatedLog; }); // Get the CURRENT state of the debugGmcp setting, not a snapshot let currentSettings = get(uiSettings); console.log('Current debugGmcp setting:', currentSettings.debugGmcp); // If debug mode is enabled, also add to normal output if (currentSettings.debugGmcp) { console.log('GMCP debug is enabled, adding to output history'); const dataString = typeof data === 'object' ? JSON.stringify(data, null, 2) : String(data); const gmcpText = `[GMCP] ${module}: ${dataString}`; addToOutputHistory(gmcpText, false, [ { pattern: '\\[GMCP\\]', color: '#8be9fd', isRegex: true }, { pattern: module, color: '#ff79c6', isRegex: false } ]); } else { console.log('GMCP debug is disabled, not adding to output history'); } } export function addToInputHistory(text: string) { inputHistory.update(history => { // Don't add empty strings or duplicates of the last command if (!text || (history.length > 0 && history[history.length - 1] === text)) { return history; } const maxSize = get(uiSettings).inputHistorySize; const updatedHistory = [...history, text]; // Limit history size if (updatedHistory.length > maxSize) { return updatedHistory.slice(updatedHistory.length - maxSize); } return updatedHistory; }); // Reset history index to point to the end inputHistoryIndex.set(-1); } export function navigateInputHistory(direction: 'up' | 'down', currentInput: string) { const history = get(inputHistory); let index = get(inputHistoryIndex); if (history.length === 0) return currentInput; if (direction === 'up') { // If we're at the beginning of navigation, save the current input if (index === -1) { inputHistory.update(h => { if (currentInput && h[h.length - 1] !== currentInput) { return [...h, currentInput]; } return h; }); } // Move up in history index = Math.min(history.length - 1, index + 1); } else if (direction === 'down') { // Move down in history index = Math.max(-1, index - 1); } inputHistoryIndex.set(index); // Return appropriate value from history or empty string if (index === -1) { return ''; } else { return history[history.length - 1 - index]; } } export function clearOutputHistory() { outputHistory.set([]); } export function updateGmcpData(module: string, data: any) { gmcpData.update(currentData => { return { ...currentData, [module]: data }; }); }