UNPKG

@hhoangphuoc/escape-room-cli

Version:

A CLI for playing AI-generated escape room games. Install globally with: npm install -g @hhoangphuoc/escape-room-cli

284 lines (283 loc) 13.7 kB
// escape-room-cli/source/utils/commandProcessor.ts import { handleHelpCommand, handleLookCommand, handleInspectCommand, handleGuessCommand, handlePasswordCommand, handleHintCommand, handleNewGameCommand, handleLeaderboardCommand, handleLogoutCommand, handleLoginCommand, handleEndSessionCommand, handleNaturalLanguageCommand, handleInstructionsCommand, handleUsageCommand, handleCostCommand, // Simplified cost monitoring - removed handlePricingCommand, handleCompareCommand, handleEstimateCommand } from './commandHandlers.js'; import { displayResponse } from './responseDisplay.js'; // import { getApiUrl } from './apiConfig.js'; // Centralized processor for all commands export const handleCommand = async (props) => { const { command, auth, game, setHistory, setIsLoading, setLoadingMessage, setShowHistory, setShowModelSelector, setShowInstructions, setShowLeaderboard, setShowCostDashboard, setShowCostMonitor, selectedModel, conversation } = props; if (command.startsWith('/')) { const parts = command.trim().split(/\s+/); const cmd = parts[0]?.toLowerCase(); const userContext = { userId: auth.userId, sessionToken: auth.sessionToken, userName: auth.userName, cliApiKey: auth.apiKey, hasAICapability: auth.apiKey ? true : false, }; const gameContext = { currentGameId: game.gameId, currentRoomName: game.roomName, currentRoomBackground: game.roomBackground, currentGameMode: game.gameMode, totalRooms: game.totalRooms, unlockedObjects: game.unlockedObjects, currentRoomObjects: game.currentRoomObjects, }; let response; switch (cmd) { case '/help': response = handleHelpCommand(userContext, gameContext); break; case '/look': response = await handleLookCommand(userContext); if (response.success && response.roomData) game.setGameFromLook(response.roomData); break; case '/inspect': const objectName = parts.slice(1).join(' '); response = await handleInspectCommand(objectName, userContext); break; case '/guess': const guessObjectName = parts.slice(1, -1).join(' '); const answer = parts[parts.length - 1]; response = await handleGuessCommand(guessObjectName, answer, userContext); if (response.success && response.objectData?.unlocked) { game.unlockObject(response.objectData.name); } break; case '/password': const password = parts.slice(1).join(' '); response = await handlePasswordCommand(password, userContext); if (response.success && response.gameResult?.gameCompleted) { game.setGameCompleted(); // Persist conversation to Firebase when game is completed if (conversation && conversation.currentConversation && conversation.persistConversation && game.gameId) { try { const persisted = await conversation.persistConversation(game.gameId); if (persisted) { } else { console.warn('Failed to save conversation history'); } } catch (error) { console.error('Failed to persist conversation on game completion:', error); } } } else if (response.success && response.gameResult?.escaped) { game.fetchGameState(); } break; case '/hint': response = await handleHintCommand(userContext); break; case '/newgame': const mode = parts[1]?.toLowerCase() || 'single-room'; setIsLoading(true); setLoadingMessage(`Preparing an AI-generated [${mode}] Escape Game...`); response = await handleNewGameCommand(mode, userContext); if (response.success && response.gameData) { game.setGame(response.gameData); // Initialize conversation for new game if (conversation && conversation.createNewConversation && response.gameData.id) { try { const sessionId = `session_${Date.now()}`; conversation.createNewConversation(String(response.gameData.id), sessionId, response.gameData.mode || 'unknown'); // Add initial system message for game start setTimeout(async () => { if (conversation.addEntry) { await conversation.addEntry({ type: 'system_message', content: `New game started: ${response.gameData.name} (${response.gameData.mode})`, metadata: { requestType: 'system', gameId: String(response.gameData.id), roomId: response.gameData.name, }, }); } }, 100); // Small delay to ensure conversation is fully initialized } catch (error) { console.error('Failed to initialize conversation for new game:', error); } } } setIsLoading(false); break; case '/leaderboard': const leaderboardMode = parts[1]?.toLowerCase() || 'time'; response = await handleLeaderboardCommand(userContext, leaderboardMode); if (response.success && response.leaderboardData) { setShowLeaderboard(response.leaderboardData); return; } break; case '/instructions': response = handleInstructionsCommand(userContext, gameContext); if (response.success) { setShowInstructions(true); return; } break; case '/logout': response = handleLogoutCommand(); auth.logout(); game.resetGame(); break; case '/end-session': response = await handleEndSessionCommand(userContext, gameContext); if (response.success) { // reset session costs client-side auth.resetSessionCosts && auth.resetSessionCosts(); // Persist conversation to Firebase if available if (conversation && conversation.currentConversation && conversation.persistConversation && game.gameId) { try { const persisted = await conversation.persistConversation(game.gameId); if (persisted) { response.message += ' Conversation history saved.'; } else { response.message += ' (Warning: Failed to save conversation history)'; } } catch (error) { response.message += ' (Warning: Failed to save conversation history)'; } } } break; case '/login': setIsLoading(true); setLoadingMessage('Attempting to login...'); response = await handleLoginCommand(); if (response.success && response.userData) { auth.login(response.userData); game.fetchGameState(); } setIsLoading(false); break; case '/register': response = { success: false, message: "To register, please restart the application without a saved session, or use CLI flags." }; break; case '/history': setShowHistory(true); return; case '/model': if (userContext.hasAICapability) { // Show model selector overlay and stop further processing setShowModelSelector(true); return; } else { response = { success: false, message: 'AI features not available. Please /login and use your API key to enable.' }; } break; case '/usage': response = await handleUsageCommand(userContext, gameContext); if (response.success && response.showUsageDashboard && response.usageData) { setShowCostDashboard(response.usageData); return; } break; case '/cost': response = await handleCostCommand(userContext, gameContext); if (response.success && response.showCostMonitor && response.costData) { setShowCostMonitor(response.costData); return; } break; // Removed /pricing, /compare, /estimate commands - simplified cost monitoring default: response = { success: false, message: `Unknown command: ${cmd}` }; } if (response) { const displayItems = displayResponse(response); setHistory((prev) => [...prev, ...displayItems]); // Track conversation if available if (conversation && conversation.addEntry && game.gameId) { try { // Add user command entry await conversation.addEntry({ type: 'user_input', content: command, metadata: { requestType: 'command', gameId: game.gameId, roomId: game.currentRoomName, }, }); // Add system response entry if (response.message) { await conversation.addEntry({ type: 'agent_response', content: response.message, metadata: { requestType: 'command', gameId: game.gameId, roomId: game.currentRoomName, }, }); } } catch (error) { console.error('Failed to track command conversation entry:', error); } } } } else { // Natural language setIsLoading(true); setLoadingMessage(`Thinking with ${selectedModel.label}...`); const userContext = { userId: auth.userId, sessionToken: auth.sessionToken, userName: auth.userName, cliApiKey: auth.apiKey, hasAICapability: auth.apiKey ? true : false, }; const response = await handleNaturalLanguageCommand(command, userContext, selectedModel); if (response) { const displayItems = displayResponse(response); setHistory((prev) => [...prev, ...displayItems]); // Track natural language conversation if (conversation && conversation.addEntry && game.gameId) { try { // Add user input entry await conversation.addEntry({ type: 'user_input', content: command, metadata: { model: selectedModel.value, requestType: 'natural_language', gameId: game.gameId, roomId: game.currentRoomName, }, }); // Add AI response entry if (response.message) { await conversation.addEntry({ type: 'agent_response', content: response.message, metadata: { model: selectedModel.value, requestType: 'natural_language', gameId: game.gameId, roomId: game.currentRoomName, }, }); } } catch (error) { console.error('Failed to track natural language conversation entry:', error); } } } setIsLoading(false); } };