"use strict"; const fs = require("fs"); Editor.Panel.extend({ style: fs.readFileSync(Editor.url("packages://mcp-bridge/panel/index.html"), "utf-8"), template: fs.readFileSync(Editor.url("packages://mcp-bridge/panel/index.html"), "utf-8"), messages: { "mcp-bridge:on-log"(event, log) { this.renderLog(log); }, "mcp-bridge:state-changed"(event, config) { this.updateUI(config.active); } }, ready() { const root = this.shadowRoot; // 获取元素 const els = { port: root.querySelector("#portInput"), btnToggle: root.querySelector("#btnToggle"), autoStart: root.querySelector("#autoStartCheck"), logView: root.querySelector("#logConsole"), tabMain: root.querySelector("#tabMain"), tabTest: root.querySelector("#tabTest"), panelMain: root.querySelector("#panelMain"), panelTest: root.querySelector("#panelTest"), toolName: root.querySelector("#toolName"), toolParams: root.querySelector("#toolParams"), toolsList: root.querySelector("#toolsList"), testBtn: root.querySelector("#testBtn"), listBtn: root.querySelector("#listToolsBtn"), clearBtn: root.querySelector("#clearTestBtn"), result: root.querySelector("#resultContent"), left: root.querySelector("#testLeftPanel"), resizer: root.querySelector("#testResizer") }; // 1. 初始化状态 Editor.Ipc.sendToMain("mcp-bridge:get-server-state", (err, data) => { if (data) { els.port.value = data.config.port; els.autoStart.value = data.autoStart; this.updateUI(data.config.active); els.logView.innerHTML = ""; data.logs.forEach(l => this.renderLog(l)); } }); // 2. 标签切换 els.tabMain.addEventListener("confirm", () => { els.tabMain.classList.add("active"); els.tabTest.classList.remove("active"); els.panelMain.classList.add("active"); els.panelTest.classList.remove("active"); }); els.tabTest.addEventListener("confirm", () => { els.tabTest.classList.add("active"); els.tabMain.classList.remove("active"); els.panelTest.classList.add("active"); els.panelMain.classList.remove("active"); this.fetchTools(els); }); // 3. 基础功能 els.btnToggle.addEventListener("confirm", () => { Editor.Ipc.sendToMain("mcp-bridge:toggle-server", parseInt(els.port.value)); }); root.querySelector("#btnClear").addEventListener("confirm", () => { els.logView.innerHTML = ""; Editor.Ipc.sendToMain("mcp-bridge:clear-logs"); }); root.querySelector("#btnCopy").addEventListener("confirm", () => { require("electron").clipboard.writeText(els.logView.innerText); Editor.success("Logs Copied"); }); els.autoStart.addEventListener("change", (e) => { Editor.Ipc.sendToMain("mcp-bridge:set-auto-start", e.target.value); }); // 4. 测试页功能 els.listBtn.addEventListener("confirm", () => this.fetchTools(els)); els.clearBtn.addEventListener("confirm", () => { els.result.value = ""; }); els.testBtn.addEventListener("confirm", () => this.runTest(els)); // 5. 【修复】拖拽逻辑 if (els.resizer && els.left) { els.resizer.addEventListener('mousedown', (e) => { e.preventDefault(); const startX = e.clientX; const startW = els.left.offsetWidth; const onMove = (ev) => { els.left.style.width = (startW + (ev.clientX - startX)) + "px"; }; const onUp = () => { document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp); document.body.style.cursor = 'default'; }; document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp); document.body.style.cursor = 'col-resize'; }); } }, fetchTools(els) { const url = `http://localhost:${els.port.value}/list-tools`; fetch(url).then(r => r.json()).then(data => { els.toolsList.innerHTML = ""; data.tools.forEach(t => { const item = document.createElement('div'); item.className = 'tool-item'; item.textContent = t.name; item.onclick = () => { els.toolName.value = t.name; els.toolParams.value = JSON.stringify(this.getExample(t.name), null, 2); }; els.toolsList.appendChild(item); }); els.result.value = `Loaded ${data.tools.length} tools.`; }).catch(e => { els.result.value = "Error: " + e.message; }); }, runTest(els) { const url = `http://localhost:${els.port.value}/call-tool`; const body = { name: els.toolName.value, arguments: JSON.parse(els.toolParams.value || "{}") }; els.result.value = "Testing..."; fetch(url, { method: 'POST', body: JSON.stringify(body) }) .then(r => r.json()) .then(d => { els.result.value = JSON.stringify(d, null, 2); }) .catch(e => { els.result.value = "Error: " + e.message; }); }, getExample(name) { const examples = { "set_node_name": { "id": "UUID", "newName": "Hello" }, "update_node_transform": { "id": "UUID", "x": 0, "y": 0, "color": "#FF0000" }, "create_node": { "name": "Node", "type": "sprite", "parentId": "" }, "open_scene": { "url": "db://assets/Scene.fire" } }; return examples[name] || {}; }, renderLog(log) { const view = this.shadowRoot.querySelector("#logConsole"); if (!view) return; const atBottom = view.scrollHeight - view.scrollTop <= view.clientHeight + 50; const el = document.createElement("div"); el.className = `log-item ${log.type}`; el.innerHTML = `${log.time}${log.content}`; view.appendChild(el); if (atBottom) view.scrollTop = view.scrollHeight; }, updateUI(active) { const btn = this.shadowRoot.querySelector("#btnToggle"); if (!btn) return; btn.innerText = active ? "Stop" : "Start"; btn.style.backgroundColor = active ? "#aa4444" : "#44aa44"; } });