window.onerror = function(msg, url, line, col, error) { document.body.innerHTML += '
ERROR: ' + msg + ' at line ' + line + '
'; }; window.addEventListener('unhandledrejection', function(event) { document.body.innerHTML += '
PROMISE REJECTION: ' + event.reason + '
'; }); try { const vscode=acquireVsCodeApi(),chat=document.getElementById('chat'),input=document.getElementById('input'), sendBtn=document.getElementById('sendBtn'),stopBtn=document.getElementById('stopBtn'), modelSel=document.getElementById('modelSel'),newChatBtn=document.getElementById('newChatBtn'),settingsBtn=document.getElementById('settingsBtn'),brainBtn=document.getElementById('brainBtn'), attachBtn=document.getElementById('attachBtn'),fileInput=document.getElementById('fileInput'),attachPreview=document.getElementById('attachPreview'), thinkingBar=document.getElementById('thinkingBar'); let loader=null,sending=false,pendingFiles=[]; /* Syntax Highlighting (lightweight) */ function highlight(code,lang){ let h=esc(code); h=h.replace(/(\\/\\/[^\\n]*)/g,'$1'); h=h.replace(/(#[^\\n]*)/g,'$1'); h=h.replace(/(\\/\\*[\\s\\S]*?\\*\\/)/g,'$1'); h=h.replace(/("[^&]*?"|'[^&]*?')/g,'$1'); h=h.replace(/\\b(function|const|let|var|return|if|else|for|while|class|import|export|from|default|async|await|try|catch|throw|new|this|def|self|print|lambda|yield|with|as|raise|except|finally)\\b/g,'$1'); h=h.replace(/\\b(\\d+\\.?\\d*)\\b/g,'$1'); h=h.replace(/\\b(True|False|None|true|false|null|undefined|NaN)\\b/g,'$1'); h=h.replace(/\\b(String|Number|Boolean|Array|Object|Map|Set|Promise|void|int|float|str|list|dict|tuple)\\b/g,'$1'); h=h.replace(/([=!<>+\\-*/%|&^~?:]+)/g,'$1'); return h; } /* Clipboard Paste (Ctrl+V images) */ input.addEventListener('paste',(e)=>{ const items=e.clipboardData&&e.clipboardData.items; if(!items)return; for(const item of items){ if(item.type.startsWith('image/')){ e.preventDefault(); const file=item.getAsFile(); if(!file)return; const reader=new FileReader(); reader.onload=()=>{ const base64=reader.result.split(',')[1]; pendingFiles.push({name:'clipboard-image.png',type:file.type,data:base64}); renderPreview(); }; reader.readAsDataURL(file); return; } } }); vscode.postMessage({type:'getModels'}); setTimeout(()=>vscode.postMessage({type:'ready'}),300); input.addEventListener('input',()=>{input.style.height='auto';input.style.height=Math.min(input.scrollHeight,150)+'px'}); function getTime(){return new Date().toLocaleTimeString('ko-KR',{hour:'2-digit',minute:'2-digit'})} function esc(s){const d=document.createElement('div');d.innerText=s;return d.innerHTML} function fmt(t){ if(t.lastIndexOf(' t.lastIndexOf('')) t += ''; if(t.lastIndexOf(' t.lastIndexOf('')) t += ''; if(t.lastIndexOf(' t.lastIndexOf('')) t += ''; if((t.match(/\`\`\`/g)||[]).length % 2 !== 0) t += '\\n\`\`\`'; const blocks = []; function pushB(h){ blocks.push(h); return '__B' + (blocks.length-1) + '__'; } t=t.replace(/([\\s\\S]*?)<\\/create_file>/g,(_,p,c)=>pushB('
\u{1F4C1} '+esc(p)+' \u2014 \uC790\uB3D9 \uC0DD\uC131\uB428
'+esc(c)+'
')); t=t.replace(/([\\s\\S]*?)<\\/edit_file>/g,(_,p,c)=>pushB('
\u270F\uFE0F '+esc(p)+' \u2014 \uD3B8\uC9D1\uB428
'+esc(c)+'
')); t=t.replace(/([\\s\\S]*?)<\\/run_command>/g,(_,c)=>pushB('
\u25B6 '+esc(c)+'
')); t=t.replace(/\`\`\`(\\w*)\\n([\\s\\S]*?)\`\`\`/g,(_,lang,c)=>{const l=lang||'code';return pushB('
'+esc(l)+'
'+highlight(c,l)+'
');}); t=t.replace(/\`([^\`]+)\`/g,(_,c)=>pushB(''+esc(c)+'')); t=esc(t); t=t.replace(/\\*\\*([^*]+)\\*\\*/g,'$1'); t=t.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, '$1'); t=t.replace(/__B(\\d+)__/g, (_,i)=>blocks[i]); return t; } function copyCode(btn){const code=btn.parentElement.querySelector('code');if(!code)return;navigator.clipboard.writeText(code.innerText).then(()=>{btn.textContent='\u2713 Copied';btn.classList.add('copied');setTimeout(()=>{btn.textContent='Copy';btn.classList.remove('copied')},1500)})} function addMsg(text,role){ const isUser=role==='user',isErr=role==='error'; const el=document.createElement('div');el.className='msg'+(isUser?' msg-user':'')+(isErr?' msg-error':''); const head=document.createElement('div');head.className='msg-head'; head.innerHTML=(isUser?'
\u{1F464}
You':'
\u2726
Connect AI')+''+getTime()+''; const body=document.createElement('div');body.className='msg-body'; if(isUser){body.innerText=text}else{body.innerHTML=fmt(text)} el.appendChild(head);el.appendChild(body);chat.appendChild(el);chat.scrollTop=chat.scrollHeight; } function showLoader(){loader=document.createElement('div');loader.className='msg';loader.innerHTML='
\u2726
Connect AI'+getTime()+'
\uC0DD\uAC01\uD558\uB294 \uC911...
';chat.appendChild(loader);chat.scrollTop=chat.scrollHeight;thinkingBar.classList.add('active')} function hideLoader(){if(loader&&loader.parentNode)loader.parentNode.removeChild(loader);loader=null;thinkingBar.classList.remove('active')} function setSending(v){sending=v;sendBtn.disabled=v;stopBtn.classList.toggle('visible',v);input.disabled=v;if(!v){input.focus();thinkingBar.classList.remove('active')}} function send(){ const text=input.value.trim(); if((!text&&pendingFiles.length===0)||sending)return; document.body.classList.remove('init'); const w=document.querySelector('.welcome');if(w)w.remove(); document.querySelectorAll('.quick-actions').forEach(e=>e.remove()); const displayText=text+(pendingFiles.length>0?' \u{1F4CE} '+pendingFiles.map(f=>f.name).join(', '):''); addMsg(displayText,'user'); input.value='';input.style.height='auto';setSending(true);showLoader(); if(pendingFiles.length>0){ vscode.postMessage({type:'promptWithFile',value:text||'\uC774 \uD30C\uC77C\uC744 \uBD84\uC11D\uD574\uC8FC\uC138\uC694.',model:modelSel.value,files:pendingFiles}); pendingFiles=[];attachPreview.innerHTML='';attachPreview.classList.remove('visible'); } else { vscode.postMessage({type:'prompt',value:text,model:modelSel.value}); } } /* Attachment Logic */ attachBtn.addEventListener('click',()=>fileInput.click()); fileInput.addEventListener('change',()=>{ const files=Array.from(fileInput.files); files.forEach(file=>{ const reader=new FileReader(); reader.onload=()=>{ const base64=reader.result.split(',')[1]; pendingFiles.push({name:file.name,type:file.type,data:base64}); renderPreview(); }; reader.readAsDataURL(file); }); fileInput.value=''; }); function renderPreview(){ attachPreview.innerHTML=''; if(pendingFiles.length===0){attachPreview.classList.remove('visible');return;} attachPreview.classList.add('visible'); pendingFiles.forEach((f,i)=>{ const chip=document.createElement('div');chip.className='attach-chip'; const isImg=f.type.startsWith('image/'); if(isImg){ const thumb=document.createElement('img');thumb.className='attach-thumb';thumb.src='data:'+f.type+';base64,'+f.data;chip.appendChild(thumb); } else { const icon=document.createElement('span');icon.className='chip-icon';icon.textContent=f.type.startsWith('audio/')?'\u{1F3A7}':'\u{1F4C4}';chip.appendChild(icon); } const nm=document.createElement('span');nm.className='chip-name';nm.textContent=f.name;chip.appendChild(nm); const rm=document.createElement('span');rm.className='chip-remove';rm.textContent='\u2715'; rm.addEventListener('click',()=>{pendingFiles.splice(i,1);renderPreview();}); chip.appendChild(rm); attachPreview.appendChild(chip); }); } document.addEventListener('click',e=>{if(e.target.classList.contains('qa-btn')){const p=e.target.getAttribute('data-prompt');if(p){input.value=p;send()}}}); sendBtn.addEventListener('click',send); input.addEventListener('keydown',e=>{if(e.key==='Enter'&&!e.shiftKey){e.preventDefault();send()}}); newChatBtn.addEventListener('click',()=>vscode.postMessage({type:'newChat'})); settingsBtn.addEventListener('click',()=>vscode.postMessage({type:'openSettings'})); brainBtn.addEventListener('click',()=>vscode.postMessage({type:'syncBrain'})); stopBtn.addEventListener('click',()=>{vscode.postMessage({type:'stopGeneration'});hideLoader();setSending(false);if(streamBody){streamBody.classList.remove('stream-active')}streamEl=null;streamBody=null;}); let streamEl=null,streamBody=null; window.addEventListener('message',e=>{const msg=e.data;switch(msg.type){ case 'response':hideLoader();setSending(false);addMsg(msg.value,'ai');break; case 'error':hideLoader();setSending(false);addMsg(msg.value,'error');break; case 'streamStart':{ hideLoader(); streamEl=document.createElement('div');streamEl.className='msg'; const h=document.createElement('div');h.className='msg-head'; h.innerHTML='
\u2726
Connect AI'+getTime()+''; streamBody=document.createElement('div');streamBody.className='msg-body stream-active'; streamEl.appendChild(h);streamEl.appendChild(streamBody);chat.appendChild(streamEl);chat.scrollTop=chat.scrollHeight; break;} case 'streamChunk':{ if(streamBody){streamBody.innerHTML=fmt(streamBody._raw=(streamBody._raw||'')+msg.value);chat.scrollTop=chat.scrollHeight;} break;} case 'streamEnd':{ if(streamBody)streamBody.classList.remove('stream-active'); /* Add regenerate button */ if(streamEl){ const rb=document.createElement('button');rb.className='regen-btn';rb.innerHTML='\u{1F504} Regenerate'; rb.addEventListener('click',()=>{rb.remove();vscode.postMessage({type:'regenerate'});showLoader();setSending(true);}); streamEl.appendChild(rb); } setSending(false);streamEl=null;streamBody=null; break;} case 'modelsList':modelSel.innerHTML='';msg.value.forEach(m=>{const o=document.createElement('option');o.value=m;o.textContent=m;modelSel.appendChild(o)});break; case 'clearChat': document.body.classList.add('init'); chat.innerHTML='
Connect AI
\uBCF4\uC548 \xB7 \uBE44\uC6A9\uCD5C\uC801\uD654 \xB7 \uC9C0\uC2DD\uC5F0\uACB0
\uD504\uB85C\uC81D\uD2B8\uB97C \uC774\uD574\uD558\uACE0, \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uACE0, \uC2E4\uD589\uD569\uB2C8\uB2E4.
'; break; case 'restoreMessages': chat.innerHTML=''; if(msg.value&&msg.value.length>0){ document.body.classList.remove('init'); msg.value.forEach(m=>addMsg(m.text,m.role)); } else { document.body.classList.add('init'); chat.innerHTML='
Connect AI
\uBCF4\uC548 \xB7 \uBE44\uC6A9\uCD5C\uC801\uD654 \xB7 \uC9C0\uC2DD\uC5F0\uACB0
\uD504\uB85C\uC81D\uD2B8\uB97C \uC774\uD574\uD558\uACE0, \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uACE0, \uC2E4\uD589\uD569\uB2C8\uB2E4.
'; } break; case 'focusInput':input.focus();break; case 'injectPrompt':input.value=msg.value;input.style.height='auto';input.style.height=Math.min(input.scrollHeight,150)+'px';send();break; } }); } catch(err) { document.body.innerHTML = '

\u26A0\uFE0F WEBVIEW JS CRASH

' + err.name + ': ' + err.message + '\\n' + err.stack + '
'; }