// devMode.js // Enhanced dev mode with harness integration for unified debugging /** * Initialize enhanced dev mode: exposes an API for stepping through state history * with integration to Baba Yaga harness versioning capabilities. * @param {object} opts * @param {function} opts.getState - returns current app state * @param {function} opts.setState - sets app state * @param {function} opts.render - triggers app re-render * @param {object} opts.harness - Baba Yaga FunctionalHarness instance (optional) */ export function initDevMode({ getState, setState, render, harness = null }) { let history = []; let pointer = -1; let firstLoad = true; let harnessCorrelation = []; // Track web state ↔ harness state correlation function pushState(state) { if (pointer < history.length - 1) history = history.slice(0, pointer + 1); history.push(clone(state)); pointer = history.length - 1; // Track correlation with harness if available if (harness) { const harnessVersion = harness.currentVersion || 0; harnessCorrelation.push({ webVersion: pointer, harnessVersion, timestamp: Date.now() }); } logInstructions(); } function goTo(idx) { if (idx < 0 || idx >= history.length) return; pointer = idx; setState(clone(history[pointer])); render(); logInstructions(); } function next() { if (pointer < history.length - 1) goTo(pointer + 1); } function prev() { if (pointer > 0) goTo(pointer - 1); } function get() { return history[pointer]; } function clone(obj) { return JSON.parse(JSON.stringify(obj)); } function table(obj) { console.table(dev.history); } // Harness integration functions function getHarnessHistory() { console.log('[DevMode] getHarnessHistory called, harness available:', !!harness); if (!harness) { console.warn('[DevMode] No harness available for versioning - run a Baba Yaga script first'); return []; } const history = harness.getVersionHistory(); console.log('[DevMode] Harness history:', history.length, 'versions'); return history; } function getHarnessDiff(from, to) { if (!harness) { console.warn('[DevMode] No harness available for diffing'); return null; } return harness.getStateDiff(from, to); } function getCorrelation() { console.log('[DevMode] getCorrelation called, harness available:', !!harness); if (!harness) { console.warn('[DevMode] No harness available for correlation - run a Baba Yaga script first'); return null; } const webState = get(); const harnessVersions = getHarnessHistory(); const currentCorrelation = harnessCorrelation.find(c => c.webVersion === pointer); const result = { webState, webVersion: pointer, harnessVersions, currentCorrelation, allCorrelations: harnessCorrelation }; console.log('[DevMode] Correlation result:', { webVersion: result.webVersion, harnessVersions: result.harnessVersions.length, correlations: result.allCorrelations.length }); return result; } function debugExecution(webVersion, harnessVersion) { if (!harness) { console.warn('[DevMode] No harness available for execution debugging'); return null; } const webState = history[webVersion]; const harnessState = harness.stateHistory.getVersion(harnessVersion); const diff = getHarnessDiff(harnessVersion - 1, harnessVersion); return { webState, harnessState, scriptDiff: diff, correlation: `Web v${webVersion} ↔ Harness v${harnessVersion}` }; } function stepCombined(direction) { if (direction === 'next') { next(); // Could also step harness if correlated const correlation = harnessCorrelation.find(c => c.webVersion === pointer); if (correlation && harness) { console.log(`[DevMode] Web v${pointer} correlates with Harness v${correlation.harnessVersion}`); } } else { prev(); } } function logInstructions() { if (firstLoad) { console.log('[DevMode] Enhanced state history debugger with harness integration'); console.log('Web App Debugging:'); console.log('- dev.next() // step forward'); console.log('- dev.prev() // step backward'); console.log('- dev.goTo(n) // jump to state n (1-based)'); console.log('- dev.get() // get current state'); console.log('- dev.table() // display history as a table'); console.log('- dev.history // array of all states'); console.log('- dev.pointer // current pointer (0-based)'); if (harness) { console.log('\nHarness Integration:'); console.log('- dev.harnessHistory() // get harness version history'); console.log('- dev.harnessDiff(from, to) // get state diff'); console.log('- dev.correlation() // show web ↔ harness correlation'); console.log('- dev.debugExecution(webVer, harnessVer) // debug specific execution'); console.log('- dev.stepCombined(direction) // step both systems'); } console.log('\nEnhanced Console API:'); console.log('- debug.web // web app debugging'); console.log('- debug.harness // harness debugging'); console.log('- debug.combined // combined debugging'); firstLoad = false; } } // Function to update harness instance (called after script execution) function updateHarness(newHarness) { console.log('[DevMode] updateHarness called with:', !!newHarness); harness = newHarness; console.log('[DevMode] Harness instance updated for enhanced debugging'); // Re-expose the enhanced debug API with updated harness window.debug = enhancedDebug; } // Function to check current dev tools status function getStatus() { return { devMode: true, webStates: history.length, currentPointer: pointer, harnessAvailable: !!harness, harnessVersions: harness ? harness.getVersionHistory().length : 0, correlations: harnessCorrelation.length }; } // Enhanced console API const enhancedDebug = { // Web app debugging web: { next, prev, goTo, get, table, get pointer() { return pointer; }, get history() { return history.slice(); }, }, // Harness debugging harness: { history: getHarnessHistory, diff: getHarnessDiff, correlation: getCorrelation, debugExecution, }, // Combined debugging combined: { correlation: getCorrelation, step: stepCombined, execution: debugExecution, status: getStatus, } }; // Expose API globally for console use window.dev = { next, prev, goTo, get, table, get pointer() { return pointer; }, get history() { return history.slice(); }, // Harness integration methods harnessHistory: getHarnessHistory, harnessDiff: getHarnessDiff, correlation: getCorrelation, debugExecution, stepCombined, updateHarness, getStatus, }; // Debug logging to verify function exposure console.log('[DevMode] Dev API functions exposed:', { updateHarness: typeof window.dev.updateHarness, getStatus: typeof window.dev.getStatus, harnessHistory: typeof window.dev.harnessHistory, correlation: typeof window.dev.correlation }); // Expose enhanced debug API window.debug = enhancedDebug; // Debug logging to verify API exposure console.log('[DevMode] Enhanced debug API exposed:', { debugAvailable: typeof window.debug !== 'undefined', webAvailable: typeof window.debug?.web !== 'undefined', harnessAvailable: typeof window.debug?.harness !== 'undefined', combinedAvailable: typeof window.debug?.combined !== 'undefined' }); // Initial state pushState(getState()); return { pushState }; }