/** * ╔══════════════════════════════════════════════════════╗ * ║ OBSIDIAN FORGE — Client Runtime ║ * ║ RLM Thought-Stream · Context Folding ║ * ║ Quantum Sandbox · Silent Handshake · Deploy ║ * ╚══════════════════════════════════════════════════════╝ */ const S = { sessionId: null, fullCode: '', previewReady: false, publishReady: false, publishData: null, handshakeVerified: false, handshakeUrl: null, deployedUrl: null, quantumWindow: null, // Reference to dedicated preview tab }; const D = { prompt: document.getElementById('prompt-input'), vibeBtn: document.getElementById('vibe-btn'), codeContent: document.getElementById('code-content'), charCount: document.getElementById('char-count'), previewFrame: document.getElementById('preview-frame'), previewOverlay: document.getElementById('preview-overlay'), previewTabBtn: document.getElementById('preview-tab-btn'), panelForge: document.getElementById('panel-forge'), panelPreview: document.getElementById('panel-preview'), publishBtn: document.getElementById('publish-btn'), deployBar: document.getElementById('deploy-bar'), deployDot: document.getElementById('deploy-dot'), deployText: document.getElementById('deploy-text'), deployLabel: document.getElementById('deploy-label'), publishResult: document.getElementById('publish-result'), liveLink: document.getElementById('live-link'), wizardHat: document.getElementById('wizard-hat'), orbitRing: document.getElementById('orbit-ring'), thoughtStream: document.getElementById('thought-stream'), streamText: document.getElementById('stream-text'), popoutBtn: document.getElementById('popout-btn'), copyBtn: document.getElementById('copy-btn'), }; /* ═══ RLM THOUGHT-STREAM NARRATION ═══ */ const RLM_NARRATIVES = { pose: [ 'Recursively partitioning the Liquid Glass layers...', 'Calibrating the RLM feedback loop for structural perfection...', 'Analyzing architectural constraints through the Obsidian lens...', 'Dispatching sub-agents to the Quantum Sandbox...', 'Mapping design topology across the neural manifold...', ], generate: [ 'Synthing frontend lattice from compressed semantic schemas...', 'Folding context vectors into the DOM manifold...', 'Applying Aetheric CSS transforms to the structural lattice...', 'Generating Liquid Glass components from RLM state...', 'Weaving the Obsidian gradient across the output surface...', ], audit: [ 'Auditing code integrity through recursive type propagation...', 'Verifying HTML topology against the Liquid Glass schema...', 'Scanning for structural anomalies in the generated lattice...', 'Cross-referencing output against the RLM design constraints...', ], heal: [ 'Applying Reflect-Select healing to identified anomalies...', 'Self-correcting structural deviations in real-time...', 'Merging healed fragments into the coherent output stream...', ], sandbox: [ 'Validating sandbox integrity through the Quantum Sandbox...', 'Performing final consistency check on the generated artifact...', 'Sealing the output in the Obsidian forge...', ], done: [ 'RLM recursion complete. Output stable.', 'Forge cycle terminated — artifact ready.', 'All sub-agents returned. Sandbox synchronized.', ], deploy: [ 'Initiating Ghost Deploy protocol...', 'Resolving DNS handshake with litheat.app...', 'Verifying deployment endpoint reachability...', 'Propagating artifact to production surface...', ], }; let _narrativeIdx = {}; function pickNarrative(phase) { const pool = RLM_NARRATIVES[phase] || RLM_NARRATIVES['pose']; if (!_narrativeIdx[phase]) _narrativeIdx[phase] = 0; const idx = _narrativeIdx[phase]++ % pool.length; return pool[idx]; } function showThoughtStream() { D.thoughtStream.style.display = 'flex'; requestAnimationFrame(() => D.thoughtStream.classList.add('visible')); } function addThoughtSentence(phase) { showThoughtStream(); const sentence = pickNarrative(phase); const el = document.createElement('span'); el.className = 'sentence'; el.textContent = sentence; D.streamText.appendChild(el); // Auto-scroll D.streamText.scrollTop = D.streamText.scrollHeight; } function clearThoughtStream() { D.streamText.innerHTML = ''; D.thoughtStream.classList.remove('visible'); } /* ═══ CONTEXT FOLDING — localStorage persistence ═══ */ const CTX_KEY = 'obsidian-forge-context'; function foldContext(data) { try { const ctx = JSON.parse(localStorage.getItem(CTX_KEY) || '{}'); Object.assign(ctx, data, {_folded: Date.now()}); localStorage.setItem(CTX_KEY, JSON.stringify(ctx)); } catch {} } function unfoldContext() { try { const ctx = JSON.parse(localStorage.getItem(CTX_KEY) || '{}'); if (ctx.lastPrompt) D.prompt.value = ctx.lastPrompt; return ctx; } catch { return {}; } } /* ═══ TAB SWITCHING ═══ */ document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', () => { if (btn.disabled) return; document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active')); btn.classList.add('active'); document.getElementById('panel-' + btn.dataset.tab).classList.add('active'); }); }); function unlockPreview() { if (S.previewReady) return; S.previewReady = true; D.previewTabBtn.disabled = false; D.previewTabBtn.classList.remove('locked'); D.previewTabBtn.querySelector('.tab-label').textContent = '🔮 View Preview'; } /* ═══ QUANTUM SANDBOX — dedicated persistent tab ═══ */ function launchQuantumSandbox(code) { const blob = new Blob([code], {type:'text/html'}); const url = URL.createObjectURL(blob); if (S.quantumWindow && !S.quantumWindow.closed) { S.quantumWindow.location.href = url; S.quantumWindow.focus(); } else { S.quantumWindow = window.open(url, 'obsidian-quantum-sandbox', 'width=1400,height=900'); } return S.quantumWindow; } function syncQuantumSandbox(code) { if (S.quantumWindow && !S.quantumWindow.closed) { const blob = new Blob([code], {type:'text/html'}); const url = URL.createObjectURL(blob); S.quantumWindow.location.href = url; } } /* ═══ WIZARD PULSE ═══ */ function pulseWizard() { D.wizardHat.classList.add('pulse'); D.orbitRing.classList.add('forging'); } function stopWizard(state) { D.wizardHat.classList.remove('pulse','stable','error','deployed'); D.orbitRing.classList.remove('forging'); if (state) D.wizardHat.classList.add(state); } /* ═══ SSE STREAMING ═══ */ async function* streamFromServer(prompt) { const resp = await fetch('/api/stream', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({prompt}) }); if (!resp.ok) throw new Error(`Stream error: ${resp.status}`); const reader = resp.body.getReader(), dec = new TextDecoder(); let buf = ''; while (true) { const {done, value} = await reader.read(); if (done) break; buf += dec.decode(value, {stream:true}); const lines = buf.split('\n'); buf = lines.pop() || ''; for (const line of lines) { if (line.startsWith('data: ')) { const d = line.slice(6); if (!d || d==='{}') continue; try { yield JSON.parse(d); } catch { yield {raw:d}; } } } } } /* ═══ IFRAME + QUANTUM ═══ */ function updateIframe(code) { const blob = new Blob([code], {type:'text/html'}); const url = URL.createObjectURL(blob); if (D.previewFrame._blobUrl) URL.revokeObjectURL(D.previewFrame._blobUrl); D.previewFrame._blobUrl = url; D.previewFrame.src = url; D.previewOverlay.classList.add('hidden'); // Sync quantum tab syncQuantumSandbox(code); } function appendCode(chunk) { if (D.codeContent.querySelector('.placeholder')) D.codeContent.innerHTML = ''; const span = document.createElement('span'); span.className='code-chunk-new'; span.textContent=chunk; D.codeContent.appendChild(span); D.codeContent.parentElement.scrollTop = D.codeContent.parentElement.scrollHeight; D.charCount.textContent = `${S.fullCode.length.toLocaleString()} chars`; } /* ═══ DEPLOY GATE ═══ */ function setDeployState(state) { D.deployBar.classList.remove('ready','verified'); D.deployDot.classList.remove('ready','verifying','deployed'); D.publishBtn.classList.remove('ready','deploying','deployed'); D.deployLabel.textContent = 'Deploy'; switch(state) { case 'ready': D.deployBar.classList.add('ready'); D.deployDot.classList.add('ready'); D.publishBtn.classList.add('ready'); D.publishBtn.disabled = false; D.deployText.textContent = 'Sandbox stable'; break; case 'verifying': D.deployDot.classList.add('verifying'); D.publishBtn.classList.add('deploying'); D.publishBtn.disabled = true; D.deployLabel.textContent = 'Verifying…'; D.deployText.textContent = 'Resolving litheat.app'; break; case 'deploying': D.deployDot.classList.add('verifying'); D.publishBtn.classList.add('deploying'); D.publishBtn.disabled = true; D.deployLabel.textContent = 'Deploying…'; D.deployText.textContent = 'Ghost Deploy active'; break; case 'deployed': D.deployBar.classList.add('verified'); D.deployDot.classList.add('deployed'); D.publishBtn.classList.add('deployed'); D.publishBtn.disabled = false; D.deployLabel.textContent = 'Live ◈'; D.deployText.textContent = 'Verified — Production ready'; break; default: D.publishBtn.disabled = true; D.deployText.textContent = 'RLM idle'; } } /* ═══ SILENT HANDSHAKE ═══ */ async function silentHandshake(urls) { for (const url of urls) { try { const resp = await fetch('/api/verify-handshake', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({url}), }); const data = await resp.json(); if (data.verified) { S.handshakeVerified = true; return {verified:true, url:data.url, latency:data.latency_ms}; } } catch {} } return {verified:false}; } /* ═══ POLL DEPLOYED URL UNTIL 200 ═══ */ async function pollUntilLive(url, maxAttempts=15) { for (let i = 0; i < maxAttempts; i++) { try { const resp = await fetch('/api/verify-handshake', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({url}), }); const data = await resp.json(); if (data.verified && data.checks?.status_code === 200) { return {live:true, url, latency:data.latency_ms}; } } catch {} await new Promise(r => setTimeout(r, 2000)); } return {live:false, url}; } /* ═══ MAIN FORGE ═══ */ async function forge() { const prompt = D.prompt.value.trim(); if (!prompt) return; S.fullCode = ''; S.previewReady = false; S.publishReady = false; S.handshakeVerified = false; S.handshakeUrl = null; S.deployedUrl = null; // Context Folding: persist user choice foldContext({lastPrompt: prompt}); // Reset document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active')); document.querySelector('.tab-btn[data-tab="forge"]').classList.add('active'); D.panelForge.classList.add('active'); D.previewTabBtn.disabled = true; D.previewTabBtn.classList.add('locked'); D.previewTabBtn.querySelector('.tab-label').textContent = '🔒 Preview'; D.codeContent.innerHTML = '// Obsidian Forge invoking RLM recursion…'; D.charCount.textContent = ''; D.previewOverlay.classList.remove('hidden'); D.previewFrame.src = 'about:blank'; D.publishResult.style.display = 'none'; setDeployState('idle'); D.vibeBtn.disabled = true; // Wizard pulse + thought-stream clearThoughtStream(); pulseWizard(); addThoughtSentence('pose'); try { for await (const ev of streamFromServer(prompt)) { if (ev.phase) { addThoughtSentence(ev.phase); } if (ev.pose) { addThoughtSentence('pose'); // Extra narration for swarm dispatch } if (ev.chunk) { appendCode(ev.chunk); S.fullCode += ev.chunk; } if (ev.partial) updateIframe(ev.partial); if (ev.sandbox) { stopWizard(ev.status === 'stable' ? 'stable' : ev.status === 'error' ? 'error' : null); if (ev.status === 'stable' || ev.status === 'published') { unlockPreview(); setDeployState('ready'); addThoughtSentence('done'); // Auto-launch quantum sandbox on stability if (S.fullCode) launchQuantumSandbox(S.fullCode); } else if (ev.status === 'error') { setDeployState('idle'); } } } } catch (err) { console.error('Forge error:', err); stopWizard('error'); addThoughtSentence('heal'); // "Self-correcting..." D.deployText.textContent = `Error: ${err.message}`; } finally { D.vibeBtn.disabled = false; if (!S.publishReady) stopWizard(null); // Persist output context foldContext({lastOutputLen: S.fullCode.length, lastForged: Date.now()}); } } /* ═══ DEPLOY WITH SILENT HANDSHAKE ═══ */ async function deploy() { if (!S.publishReady && !S.fullCode) return; // Phase 1: Silent DNS handshake — verify litheat.app FIRST setDeployState('verifying'); clearThoughtStream(); addThoughtSentence('deploy'); const hk = await silentHandshake(['litheat.app', 'huggingface.co']); if (hk.verified) { addThoughtSentence('deploy'); } else { // Retry once await new Promise(r => setTimeout(r, 1500)); const hk2 = await silentHandshake(['litheat.app']); if (hk2.verified) { addThoughtSentence('deploy'); } else { D.deployText.textContent = 'Handshake failed — retry'; setDeployState('ready'); return; } } // Phase 2: Publish setDeployState('deploying'); const repoName = `obsidian-${Date.now().toString(36)}`; addThoughtSentence('deploy'); try { const resp = await fetch('/api/publish', { method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({repo_name:repoName, description:D.prompt.value.trim().slice(0,200)}), }); const r = await resp.json(); if (r.success) { S.publishData = r; const rawUrl = r.spaces?.url || r.tunnel_url || ''; S.deployedUrl = rawUrl; // Phase 3: Poll until 200 — do NOT show URL until verified D.deployText.textContent = 'Polling deployment…'; D.deployLabel.textContent = 'Checking…'; const live = await pollUntilLive(rawUrl); if (live.live) { // Only now reveal the URL stopWizard('deployed'); setDeployState('deployed'); D.publishResult.style.display = 'block'; D.liveLink.href = live.url; D.liveLink.textContent = live.url; foldContext({lastDeployUrl: live.url, lastDeployed: Date.now()}); addThoughtSentence('deploy'); D.publishResult.scrollIntoView({behavior:'smooth',block:'nearest'}); } else { // Still show but warn stopWizard('deployed'); setDeployState('deployed'); D.publishResult.style.display = 'block'; D.liveLink.href = rawUrl; D.liveLink.textContent = rawUrl + ' (propagating)'; D.deployText.textContent = 'Deployed — warming up'; } } else { D.deployText.textContent = `Error: ${r.error || r.space_error || 'Unknown'}`; setDeployState('ready'); } } catch (err) { D.deployText.textContent = `Error: ${err.message}`; setDeployState('ready'); } } /* ═══ QUANTUM SANDBOX POPOUT ═══ */ D.popoutBtn.addEventListener('click', () => { if (S.fullCode) launchQuantumSandbox(S.fullCode); }); /* ═══ EVENT BINDINGS ═══ */ D.vibeBtn.addEventListener('click', forge); D.publishBtn.addEventListener('click', deploy); D.prompt.addEventListener('keydown', e => { if (e.key==='Enter' && !e.shiftKey) { e.preventDefault(); forge(); } }); D.copyBtn.addEventListener('click', async () => { if (!S.fullCode) return; try { await navigator.clipboard.writeText(S.fullCode); } catch {} }); /* ═══ AUTO-RESIZE ═══ */ D.prompt.addEventListener('input', () => { D.prompt.style.height = 'auto'; D.prompt.style.height = Math.min(D.prompt.scrollHeight, 110) + 'px'; }); /* ═══ CONTEXT FOLDING: restore on load ═══ */ (function restoreContext() { const ctx = unfoldContext(); if (ctx.lastPrompt) { D.prompt.value = ctx.lastPrompt; D.prompt.style.height = 'auto'; D.prompt.style.height = Math.min(D.prompt.scrollHeight, 110) + 'px'; } })(); console.log('◈ Obsidian Forge — Kinetic RLM Environment ready'); console.log(' RLM: Recursive Language Modeling active'); console.log(' Context Folding: localStorage persistence'); console.log(' Quantum Sandbox: dedicated tab sync'); console.log(' Handshake: silent DNS + poll-until-live');