diff --git a/emrg/gui/daemon_client.js b/emrg/gui/daemon_client.js index fefb5c74..76a48495 100644 --- a/emrg/gui/daemon_client.js +++ b/emrg/gui/daemon_client.js @@ -44,6 +44,7 @@ const RESPONSE_TYPES = { compact: "compact_result", rewind_session: "rewind_result", // 补缺:daemon.py:955 rewind_result read_memory: "memory_content", // 补缺:daemon.py:771/778 memory_content + evolution_summary: "evolution_summary", // WorkBuddy P3:自进化可见化 }; class DaemonClient { diff --git a/emrg/gui/main.js b/emrg/gui/main.js index 9e23e86b..70f1dd00 100644 --- a/emrg/gui/main.js +++ b/emrg/gui/main.js @@ -436,6 +436,12 @@ vision = false return { ok: true, count: frame.count ?? 0 }; }); + ipcMain.handle("emrg:evolutionSummary", async (_e, { limit = 5 } = {}) => { + // GUI / 指令 P3:自进化可见化 — daemon evolution_summary(count + 最近改进) + const frame = await client.sendCommandAndWait("evolution_summary", { limit }, 5000); + return { count: frame.count ?? 0, recent: frame.recent || [] }; + }); + ipcMain.handle("emrg:setModel", async (_e, { model }) => { await client.sendCommandAndWait("set_model", { model }, 5000); return { ok: true }; diff --git a/emrg/gui/preload.js b/emrg/gui/preload.js index 5ced7cdd..197b2bef 100644 --- a/emrg/gui/preload.js +++ b/emrg/gui/preload.js @@ -26,6 +26,7 @@ const api = { listTasks: () => ipcRenderer.invoke("emrg:listTasks"), triggerTask: (payload) => ipcRenderer.invoke("emrg:triggerTask", payload), sendRant: (payload) => ipcRenderer.invoke("emrg:sendRant", payload), + evolutionSummary: (payload) => ipcRenderer.invoke("emrg:evolutionSummary", payload), listModels: () => ipcRenderer.invoke("emrg:listModels"), openFile: (payload) => ipcRenderer.invoke("emrg:openFile", payload), saveSettings: (payload) => ipcRenderer.invoke("emrg:saveSettings", payload), diff --git a/emrg/gui/renderer/css/components.css b/emrg/gui/renderer/css/components.css index bfa7c3c7..16ff50ca 100644 --- a/emrg/gui/renderer/css/components.css +++ b/emrg/gui/renderer/css/components.css @@ -954,3 +954,39 @@ dialog::backdrop { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } + +/* WorkBuddy P3:设置 → 关于区 */ +.about-row { + font-size: var(--fs-secondary, 13px); + color: var(--text-2); + margin-bottom: 4px; +} +.about-row b { color: var(--accent); } +.about-recent { + margin-top: 6px; + max-height: 180px; + overflow-y: auto; +} +.about-recent-title { + font-size: var(--fs-aux, 12px); + font-weight: 600; + color: var(--text-3); + margin-bottom: 4px; +} +.about-recent-item { + display: flex; + align-items: center; + gap: 8px; + font-size: var(--fs-aux, 12px); + color: var(--text-2); + padding: 4px 0; + border-bottom: 1px solid var(--border); +} +.about-recent-item:last-child { border-bottom: none; } +.about-recent-time { + font-family: var(--font-mono, monospace); + color: var(--text-3); + white-space: nowrap; + font-size: 11px; +} +} diff --git a/emrg/gui/renderer/index.html b/emrg/gui/renderer/index.html index f1279865..107eb803 100644 --- a/emrg/gui/renderer/index.html +++ b/emrg/gui/renderer/index.html @@ -140,6 +140,11 @@

设置

EMRG 是一个会自我进化的 AI 智能体——每次改进都会自动汇报,你可以随时在这里看到它的成长。
+ +
+
最近改进
+
+
diff --git a/emrg/gui/renderer/js/app.js b/emrg/gui/renderer/js/app.js index 822aa12c..70bf7d02 100644 --- a/emrg/gui/renderer/js/app.js +++ b/emrg/gui/renderer/js/app.js @@ -734,6 +734,34 @@ const App = (() => { if (dismiss) dismiss.addEventListener("click", hideEvolutionToast); } + async function loadEvolutionSummary() { + const recent = $("about-recent"); + if (!recent) return; + try { + const res = await window.emrg.evolutionSummary({ limit: 5 }); + if (res && res.count !== undefined) { + state.evolutionCount = res.count; + updateGrowthCard(); + } + const items = (res && res.recent) || []; + recent.innerHTML = ""; + if (items.length === 0) { + recent.appendChild(el("div", { class: "about-recent-item" }, "还没有改进记录,输入 /rant 驱动第一次进化吧")); + return; + } + const header = el("div", { class: "about-recent-title" }, "最近改进"); + recent.appendChild(header); + for (const it of items) { + const ts = String(it.timestamp || "").slice(0, 16).replace("T", " "); + const ops = (it.operations || []).join(" · "); + const row = el("div", { class: "about-recent-item" }); + row.appendChild(el("span", { class: "about-recent-time" }, ts)); + row.appendChild(el("span", {}, ops || "self-improvement")); + recent.appendChild(row); + } + } catch { /* 摘要加载失败静默(进化卡仍显示 count) */ } + } + function initModelSwitcher() { const sw = $("model-switcher"); sw.addEventListener("click", async (e) => { @@ -992,7 +1020,10 @@ const App = (() => { $("send-btn").addEventListener("click", sendMessage); $("stop-btn").addEventListener("click", () => window.emrg.cancel().catch(() => {})); $("new-chat-btn").addEventListener("click", newSession); - $("settings-btn").addEventListener("click", Dialogs.showSettings); + $("settings-btn").addEventListener("click", () => { + loadEvolutionSummary(); // WorkBuddy P3:打开设置时加载最近改进 + Dialogs.showSettings(); + }); $("settings-cancel").addEventListener("click", () => $("settings-dialog").close()); $("settings-save").addEventListener("click", Dialogs.saveSettings); $("pick-dir-btn").addEventListener("click", async () => { @@ -1163,6 +1194,7 @@ const App = (() => { maybeShowEvolutionToast, // WorkBuddy P3:进化 toast 检测 showVersionInfo, // WorkBuddy P3:/version 内容(toast "去看看" 共用) setMode, // WorkBuddy P2:Ask/Auto 模式(导出供测试与外部调用) + loadEvolutionSummary, // WorkBuddy P3:最近改进摘要 }; })(); diff --git a/emrg/gui/renderer/js/result-panel.js b/emrg/gui/renderer/js/result-panel.js index 6896ee85..f30cab55 100644 --- a/emrg/gui/renderer/js/result-panel.js +++ b/emrg/gui/renderer/js/result-panel.js @@ -170,3 +170,7 @@ const ResultPanel = (() => { return { init, addToolResult, toggle, isCollapsed }; })(); + +// ⚠️ 必须暴露到 window:app.js 作为独立