Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion emrg/gui/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 安全:contextIsolation + nodeIntegration:false + sandbox:true(renderer 零网络权限)。
*/

const { app, BrowserWindow, dialog, ipcMain } = require("electron");
const { app, BrowserWindow, dialog, ipcMain, shell } = require("electron");
const fs = require("fs");
const os = require("os");
const path = require("path");
Expand Down Expand Up @@ -438,6 +438,15 @@ vision = false
return { ok: true };
});

ipcMain.handle("emrg:openFile", async (_e, { filePath }) => {
// GUI / 指令 WorkBuddy P1:产物面板打开文件(系统默认程序)
if (typeof filePath !== "string" || !filePath.trim()) throw new Error("invalid file path");
const p = path.resolve(filePath.trim());
if (!fs.existsSync(p)) return { ok: false, error: "file_not_found" };
const err = await shell.openPath(p);
return { ok: err === "", error: err || "" };
});

ipcMain.handle("emrg:listModels", async () => {
const frame = await client.sendCommandAndWait("list_models", {}, 5000);
return frame.models || [];
Expand Down
1 change: 1 addition & 0 deletions emrg/gui/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const api = {
triggerTask: (payload) => ipcRenderer.invoke("emrg:triggerTask", payload),
sendRant: (payload) => ipcRenderer.invoke("emrg:sendRant", payload),
listModels: () => ipcRenderer.invoke("emrg:listModels"),
openFile: (payload) => ipcRenderer.invoke("emrg:openFile", payload),
saveSettings: (payload) => ipcRenderer.invoke("emrg:saveSettings", payload),
getSettings: () => ipcRenderer.invoke("emrg:getSettings"),
cancel: () => ipcRenderer.invoke("emrg:cancel"),
Expand Down
168 changes: 168 additions & 0 deletions emrg/gui/renderer/css/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,171 @@ body.sidebar-collapsed #app {
padding: var(--sp-2) var(--sp-3) var(--sp-3);
}
}

/* ── 结果面板(右栏 Artifacts,WorkBuddy P1) ─────────────── */
#result-panel {
width: 280px;
min-width: 240px;
display: flex;
flex-direction: column;
background: var(--bg-panel);
border-left: 1px solid var(--border);
overflow: hidden;
transition: width 0.2s cubic-bezier(.2,.8,.3,1), min-width 0.2s cubic-bezier(.2,.8,.3,1);
}
#result-panel.collapsed {
width: 0;
min-width: 0;
border-left: none;
}
#result-panel.collapsed .result-header,
#result-panel.collapsed .result-list {
display: none;
}

.result-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--sp-3) var(--sp-4);
border-bottom: 1px solid var(--border);
white-space: nowrap;
}
.result-title {
font-size: var(--fs-secondary);
font-weight: 600;
color: var(--text-1);
}
.result-toggle {
background: none;
border: none;
color: var(--text-3);
font-size: 16px;
cursor: pointer;
padding: 2px 6px;
border-radius: 6px;
}
.result-toggle:hover {
color: var(--text-1);
background: var(--bg-soft);
}

.result-list {
flex: 1;
overflow-y: auto;
padding: var(--sp-3);
display: flex;
flex-direction: column;
gap: var(--sp-2);
}
.result-empty {
color: var(--text-3);
font-size: var(--fs-secondary);
text-align: center;
padding: var(--sp-6) var(--sp-3);
line-height: 1.6;
}

/* 产物卡片 */
.result-item {
border: 1px solid var(--border);
border-radius: 10px;
background: var(--bg);
overflow: hidden;
}
.result-item.done { border-left: 3px solid var(--accent); }
.result-item.failed { border-left: 3px solid var(--red); }
.result-head {
display: flex;
align-items: center;
gap: var(--sp-2);
padding: var(--sp-2) var(--sp-3);
cursor: pointer;
user-select: none;
}
.result-tool {
font-size: var(--fs-secondary);
font-weight: 600;
color: var(--text-1);
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.result-elapsed {
font-size: 11px;
color: var(--text-3);
}
.result-chevron {
color: var(--text-3);
font-size: 10px;
transition: transform 0.15s;
}
.result-item.expanded .result-chevron {
transform: rotate(180deg);
}
.result-body {
padding: var(--sp-2) var(--sp-3) var(--sp-3);
font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
font-size: 11px;
color: var(--text-2);
border-top: 1px solid var(--border);
white-space: pre-wrap;
word-break: break-all;
max-height: 180px;
overflow-y: auto;
position: relative;
}
.result-copy {
position: sticky;
bottom: 4px;
float: right;
margin: 4px 0 0 8px;
font-size: 11px;
padding: 2px 8px;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--bg-panel);
color: var(--text-2);
cursor: pointer;
}
.result-copy:hover {
color: var(--accent);
border-color: var(--accent);
}
.result-file {
padding: var(--sp-2) var(--sp-3);
border-top: 1px solid var(--border);
font-size: var(--fs-secondary);
cursor: pointer;
color: var(--blue);
display: flex;
align-items: center;
gap: var(--sp-2);
}
.result-file::before {
content: "📄";
font-size: 12px;
}
.result-file:hover {
background: var(--accent-soft);
color: var(--accent);
}
.result-filename {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

/* 窄屏(<900px)自动隐藏 */
@media (max-width: 900px) {
#result-panel {
width: 0;
min-width: 0;
border-left: none;
}
#result-panel .result-header,
#result-panel .result-list {
display: none;
}
}
10 changes: 10 additions & 0 deletions emrg/gui/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,15 @@
<div class="composer-hint">EMRG 可能会犯错,请核对重要信息</div>
</div>
</main>

<!-- 结果面板(右栏 Artifacts,WorkBuddy P1) -->
<aside id="result-panel">
<div class="result-header">
<span class="result-title">产物</span>
<button id="result-toggle" class="result-toggle" title="折叠/展开 (⌘\)">»</button>
</div>
<div id="result-list" class="result-list"></div>
</aside>
</div>

<!-- 设置对话框 -->
Expand Down Expand Up @@ -281,6 +290,7 @@ <h2>后台任务</h2>
<script src="js/chat.js"></script>
<script src="js/sidebar.js"></script>
<script src="js/dialogs.js"></script>
<script src="js/result-panel.js"></script>
<script src="js/app.js"></script>
</body>
</html>
2 changes: 2 additions & 0 deletions emrg/gui/renderer/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ const App = (() => {
break;
case "tool_finished":
Chat.handleToolEnd(data);
ResultPanel.addToolResult(data);
break;
case "cancelled":
state.busy = false;
Expand Down Expand Up @@ -1042,6 +1043,7 @@ const App = (() => {
Dialogs.initModelForm();
Dialogs.initRenameDialog();
initModelSwitcher();
ResultPanel.init(); // WorkBuddy P1:结果面板(⌘\ 折叠 + 窄屏自动隐藏)
}

// ── 暴露 ─────────────────────────────────
Expand Down
Loading
Loading