(function () { const vscode = acquireVsCodeApi(); const feedScrollEl = document.getElementById("feed-scroll"); const headerRagSessionEl = document.getElementById("header-rag-session"); const headerRagSessionValueEl = document.getElementById("header-rag-session-value"); const processVersionEl = document.getElementById("process-version"); const statusBlocksEl = document.getElementById("status-blocks"); const messagesEl = document.getElementById("messages"); const inputEl = document.getElementById("input"); const btnSend = document.getElementById("btn-send"); const btnClear = document.getElementById("btn-clear"); const btnMenu = document.getElementById("btn-menu"); const menuDropdown = document.getElementById("menu-dropdown"); const taskStatusEl = document.getElementById("task-status"); const taskStatusLabelEl = document.getElementById("task-status-label"); const taskStatusDetailEl = document.getElementById("task-status-detail"); const taskProgressEl = document.getElementById("task-progress"); const taskProgressBarEl = document.getElementById("task-progress-bar"); const ragDotEl = document.getElementById("rag-dot"); const ragLabelEl = document.getElementById("rag-label"); const ragDetailEl = document.getElementById("rag-detail"); const ragMetricsEl = document.getElementById("rag-metrics"); let currentRagSessionId = ""; function renderStatusBlocks(items) { statusBlocksEl.innerHTML = ""; (items || []).forEach(function (block) { const wrap = document.createElement("div"); wrap.className = "status-block"; const title = document.createElement("div"); title.className = "status-block-title"; title.textContent = block.title || block.id || "Status"; wrap.appendChild(title); const body = document.createElement("div"); body.className = "status-block-body"; (block.lines || []).forEach(function (line) { const item = document.createElement("div"); item.className = "status-block-line"; item.textContent = line || ""; body.appendChild(item); }); wrap.appendChild(body); statusBlocksEl.appendChild(wrap); }); } function renderMessages(items) { messagesEl.innerHTML = ""; (items || []).forEach(function (m) { const div = document.createElement("div"); var roleClass = "msg-assistant"; if (m.role === "user") { roleClass = "msg-user"; } else if (m.role === "status") { roleClass = "msg-status"; } else if (m.role === "error") { roleClass = "msg-error"; } div.className = "msg " + roleClass; const text = document.createElement("div"); text.className = m.kind === "markdown" ? "msg-markdown" : "msg-text"; text.textContent = m.text || ""; if (m.role !== "status") { const role = document.createElement("div"); role.className = "msg-role"; role.textContent = m.role === "user" ? "Вы" : m.role === "error" ? "Ошибка" : "Ответ"; div.appendChild(role); } div.appendChild(text); messagesEl.appendChild(div); }); } function renderTaskStatus(status) { var visible = Boolean(status && status.visible); taskStatusEl.hidden = !visible; if (!visible) { taskProgressEl.hidden = true; taskProgressBarEl.style.width = "0%"; return; } taskStatusLabelEl.textContent = status.label || "Статус"; taskStatusDetailEl.textContent = status.detail || ""; if (typeof status.progress === "number" && isFinite(status.progress)) { taskProgressEl.hidden = false; taskProgressBarEl.style.width = Math.max(0, Math.min(100, status.progress)) + "%"; } else { taskProgressEl.hidden = true; taskProgressBarEl.style.width = "0%"; } } function renderRagStatus(status) { var state = (status && status.state) || "idle"; var sessionId = (status && status.ragSessionId) || ""; currentRagSessionId = sessionId; ragDotEl.className = "rag-dot state-" + state; ragLabelEl.textContent = (status && status.label) || "RAG не готов"; ragDetailEl.textContent = (status && status.detail) || "Ожидается индексация проекта."; if (headerRagSessionEl && headerRagSessionValueEl) { headerRagSessionValueEl.textContent = sessionId || "—"; headerRagSessionEl.title = sessionId ? "Кликните, чтобы скопировать RAG session id" : "RAG session is not created yet."; } var metrics = []; if (status) { metrics.push("indexed: " + (status.indexedFiles || 0)); metrics.push("failed: " + (status.failedFiles || 0)); metrics.push("cache hit: " + (status.cacheHitFiles || 0)); metrics.push("cache miss: " + (status.cacheMissFiles || 0)); } ragMetricsEl.textContent = metrics.join(" | "); } function renderState(state) { renderStatusBlocks(state.statusBlocks); renderMessages(state.messages); renderTaskStatus(state.taskStatus); renderRagStatus(state.ragStatus); if (processVersionEl && state && state.processVersion) { processVersionEl.value = state.processVersion; } btnSend.disabled = false; inputEl.disabled = false; btnClear.disabled = Boolean(state.busy); if (feedScrollEl) { feedScrollEl.scrollTop = feedScrollEl.scrollHeight; } } window.addEventListener("message", function (event) { const msg = event.data; if (msg && msg.type === "state") { renderState(msg.payload || {}); } }); function send() { const text = (inputEl.value || "").trim(); if (!text) { return; } vscode.postMessage({ type: "send", text: text }); inputEl.value = ""; } btnSend.addEventListener("click", send); inputEl.addEventListener("keydown", function (e) { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); send(); } }); btnClear.addEventListener("click", function () { vscode.postMessage({ type: "clear" }); }); processVersionEl.addEventListener("change", function () { vscode.postMessage({ type: "set-process-version", value: processVersionEl.value || "v2", }); }); async function copyRagSessionId() { if (!currentRagSessionId) { return; } try { if (navigator.clipboard && typeof navigator.clipboard.writeText === "function") { await navigator.clipboard.writeText(currentRagSessionId); } else { const helper = document.createElement("textarea"); helper.value = currentRagSessionId; helper.style.position = "fixed"; helper.style.opacity = "0"; document.body.appendChild(helper); helper.focus(); helper.select(); document.execCommand("copy"); document.body.removeChild(helper); } if (headerRagSessionEl) { headerRagSessionEl.classList.add("copied"); window.setTimeout(function () { headerRagSessionEl.classList.remove("copied"); }, 1200); } } catch (error) { console.error("Failed to copy RAG session id", error); } } headerRagSessionEl.addEventListener("click", function () { void copyRagSessionId(); }); headerRagSessionEl.addEventListener("keydown", function (event) { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); void copyRagSessionId(); } }); btnMenu.addEventListener("click", function (e) { e.stopPropagation(); const open = menuDropdown.hidden; menuDropdown.hidden = !open; btnMenu.setAttribute("aria-expanded", open ? "true" : "false"); }); document.addEventListener("click", function () { if (!menuDropdown.hidden) { menuDropdown.hidden = true; btnMenu.setAttribute("aria-expanded", "false"); } }); menuDropdown.addEventListener("click", function (e) { e.stopPropagation(); const t = e.target; if (t && t.classList && t.classList.contains("menu-item")) { const action = t.getAttribute("data-action") || ""; vscode.postMessage({ type: "menu", action: action }); menuDropdown.hidden = true; btnMenu.setAttribute("aria-expanded", "false"); } }); vscode.postMessage({ type: "ready" }); })();