UNPKG

qnce-engine

Version:

Core QNCE (Quantum Narrative Convergence Engine) - Framework agnostic narrative engine with performance optimization

259 lines 9.13 kB
#!/usr/bin/env node "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.playInteractive = main; const fs_1 = require("fs"); const readline_1 = require("readline"); const core_js_1 = require("../engine/core.js"); const demo_story_js_1 = require("../engine/demo-story.js"); function displayNode(session) { const { engine } = session; const currentNode = engine.getCurrentNode(); const choices = engine.getAvailableChoices(); console.log('\n' + '='.repeat(60)); console.log(currentNode.text); console.log('='.repeat(60)); if (choices.length > 0) { console.log('\nChoices:'); choices.forEach((choice, index) => { console.log(`${index + 1}. ${choice.text}`); }); } else { console.log('\n[Story Complete]'); } // Show undo/redo status const undoCount = engine.getUndoCount(); const redoCount = engine.getRedoCount(); console.log(`\nUndo: ${undoCount} available | Redo: ${redoCount} available`); } function displayHelp() { console.log('\nCommands:'); console.log(' 1-9 : Select choice by number'); console.log(' u, undo : Undo last action'); console.log(' r, redo : Redo last undone action'); console.log(' h, help : Show this help'); console.log(' s, save : Save current state'); console.log(' l, load : Load saved state'); console.log(' f, flags: Show current flags'); console.log(' hist : Show history summary'); console.log(' q, quit : Exit the session'); } function displayFlags(session) { const { engine } = session; const flags = engine.getState().flags; console.log('\n--- Current Flags ---'); if (Object.keys(flags).length === 0) { console.log('No flags set'); } else { Object.entries(flags).forEach(([key, value]) => { console.log(`${key}: ${JSON.stringify(value)}`); }); } } function displayHistory(session) { const { engine } = session; const summary = engine.getHistorySummary(); console.log('\n--- History Summary ---'); console.log(`Undo entries: ${summary.undoEntries.length}`); console.log(`Redo entries: ${summary.redoEntries.length}`); if (summary.undoEntries.length > 0) { console.log('\nRecent undo history:'); summary.undoEntries.slice(-5).forEach((entry, index) => { console.log(` ${index + 1}. ${entry.action || 'Action'} (${entry.timestamp})`); }); } } async function saveState(session) { const { engine, rl } = session; return new Promise((resolve) => { rl.question('Enter filename to save (or press Enter for default): ', async (filename) => { const saveFile = filename || 'qnce-save.json'; try { const serializedState = await engine.saveState({ includeFlowEvents: true }); require('fs').writeFileSync(saveFile, JSON.stringify(serializedState, null, 2)); console.log(`✅ State saved to ${saveFile}`); } catch (error) { console.error('❌ Failed to save state:', error?.message || error); } resolve(); }); }); } async function loadState(session) { const { engine, rl } = session; return new Promise((resolve) => { rl.question('Enter filename to load (or press Enter for default): ', async (filename) => { const loadFile = filename || 'qnce-save.json'; try { const data = (0, fs_1.readFileSync)(loadFile, 'utf-8'); const serializedState = JSON.parse(data); await engine.loadState(serializedState); console.log(`✅ State loaded from ${loadFile}`); displayNode(session); } catch (error) { console.error('❌ Failed to load state:', error?.message || error); } resolve(); }); }); } function handleCommand(session, input) { const { engine } = session; const choices = engine.getAvailableChoices(); return new Promise((resolve) => { const command = input.trim().toLowerCase(); // Handle numeric choices const choiceNumber = parseInt(command); if (!isNaN(choiceNumber) && choiceNumber >= 1 && choiceNumber <= choices.length) { const selectedChoice = choices[choiceNumber - 1]; engine.selectChoice(selectedChoice); displayNode(session); resolve(false); return; } // Handle text commands switch (command) { case 'u': case 'undo': const undoResult = engine.undo(); if (undoResult.success) { console.log(`✅ Undid: ${undoResult.entry?.action || 'action'}`); displayNode(session); } else { console.log('❌ Nothing to undo'); } resolve(false); break; case 'r': case 'redo': const redoResult = engine.redo(); if (redoResult.success) { console.log(`✅ Redid: ${redoResult.entry?.action || 'action'}`); displayNode(session); } else { console.log('❌ Nothing to redo'); } resolve(false); break; case 'h': case 'help': displayHelp(); resolve(false); break; case 'f': case 'flags': displayFlags(session); resolve(false); break; case 'hist': displayHistory(session); resolve(false); break; case 's': case 'save': saveState(session).then(() => resolve(false)); break; case 'l': case 'load': loadState(session).then(() => resolve(false)); break; case 'q': case 'quit': console.log('👋 Thanks for playing!'); resolve(true); break; default: console.log('❓ Unknown command. Type "help" for available commands.'); resolve(false); break; } }); } async function startInteractiveSession(session) { const { rl } = session; console.log('🎮 QNCE Interactive Session Started'); console.log('Type "help" for available commands'); // Configure undo/redo and autosave session.engine.configureUndoRedo({ enabled: true, maxUndoEntries: 100, maxRedoEntries: 50 }); session.engine.configureAutosave({ enabled: true, triggers: ['choice', 'flag-change'], throttleMs: 100, maxEntries: 20, includeMetadata: true }); displayNode(session); const promptUser = async () => { return new Promise((resolve) => { rl.question('\n> ', async (input) => { const shouldQuit = await handleCommand(session, input); if (shouldQuit) { rl.close(); resolve(); } else { await promptUser(); resolve(); } }); }); }; await promptUser(); } function main() { const args = process.argv.slice(2); if (args.includes('--help') || args.includes('-h')) { console.log('QNCE Interactive CLI'); console.log('Usage: qnce-play [story-file.json]'); console.log(''); console.log('If no story file is provided, the demo story will be used.'); console.log(''); console.log('Commands during play:'); displayHelp(); return; } let storyData; const storyFile = args[0]; if (storyFile) { try { console.log(`📖 Loading story: ${storyFile}`); const jsonData = JSON.parse((0, fs_1.readFileSync)(storyFile, 'utf-8')); storyData = (0, core_js_1.loadStoryData)(jsonData); } catch (error) { console.error(`❌ Failed to load story file: ${error?.message || error}`); process.exit(1); } } else { console.log('📖 Using demo story'); storyData = demo_story_js_1.DEMO_STORY; } const engine = (0, core_js_1.createQNCEEngine)(storyData); const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout }); const session = { engine, rl }; startInteractiveSession(session).catch((error) => { console.error('❌ Session error:', error.message); process.exit(1); }); } // Run if called directly if (process.argv[1] && process.argv[1].endsWith('play.js')) { main(); } //# sourceMappingURL=play.js.map