diff --git a/Agent.md b/Agent.md index 2530a48a..9b116dc3 100644 --- a/Agent.md +++ b/Agent.md @@ -85,7 +85,7 @@ Usage: say "tool loop" for the whole process, "round N" for a single LLM request - Streaming chat with delta rendering (16ms batching), markdown on done (marked + DOMPurify + local highlight.js subset), tool call status cards (2000-char truncation + expand) - Session list/switch/new/delete + right-click rename (context menu, #423) synced with daemon; own-stream busy lock (G65); broadcast streams from other clients tagged "来自其他客户端" - Disconnect/reconnect: red status dot, auto daemon respawn (stale-port detection), session resume, input bar restored on disconnect (no 30s fake-timeout) - - Unit tests `npm test` (256: 45 daemon_client + 19 conn-manager + 22 app-commands + 127 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group); RESPONSE_TYPES mirror daemon protocol verified against `daemon.py` + - Unit tests `npm test` (255: 45 daemon_client + 19 conn-manager + 22 app-commands + 126 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group); RESPONSE_TYPES mirror daemon protocol verified against `daemon.py` - **Scheduled tasks** — Task generalization + CRUD (rant 2026-08-12T18:23:15, #709/#710/#711) - Task handler generalized: `TaskHandler` (renamed from `EvolutionHandler`), repo-configured self-heal for any project, template lookup builtin → `~/.emrg/task-templates/.md` → fallback - Daemon commands: `task_create/update/delete` + `task_template_create/list/update/delete` (tasks stored in `~/.emrg/tasks.yml`, custom type templates in `~/.emrg/task-templates/`) @@ -119,7 +119,7 @@ pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.token; python -m emrg ``` Python: `uv run pytest tests/ -v` (988) — import check: `uv run python -c "from emrg.client.app import run_client"` -GUI: `cd emrg/gui && npm test` (256: 45 daemon_client + 19 conn-manager + 22 app-commands + 127 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` +GUI: `cd emrg/gui && npm test` (255: 45 daemon_client + 19 conn-manager + 22 app-commands + 126 renderer smoke + 15 i18n + 8 integration + 3 commands + 8 build-config + 7 gui-state + 2 tool-group) — syntax: `node --check main.js preload.js daemon_client.js renderer/js/*.js` CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文) Re-trigger: `scripts/re-trigger-ci.sh [branch]` (workflow_dispatch, #527 — 替代空 commit 重触发:Actions outage 会整段丢弃 push 事件,dispatch 走 API 路径不受影响) diff --git a/emrg/gui/renderer/css/components.css b/emrg/gui/renderer/css/components.css index e274b4bf..aeac0d59 100644 --- a/emrg/gui/renderer/css/components.css +++ b/emrg/gui/renderer/css/components.css @@ -19,12 +19,6 @@ background: var(--bg-soft); color: var(--text-1); } -/* 键盘导航聚焦(↑↓)——区别于当前会话高亮 */ -.conv-item.kbd-focus { - outline: 2px solid var(--accent); - outline-offset: -2px; - background: var(--bg-soft); -} .conv-item.active { background: var(--accent-soft); color: var(--accent); diff --git a/emrg/gui/renderer/index.html b/emrg/gui/renderer/index.html index b5c86150..9877985f 100644 --- a/emrg/gui/renderer/index.html +++ b/emrg/gui/renderer/index.html @@ -39,7 +39,6 @@ - diff --git a/emrg/gui/renderer/js/app.js b/emrg/gui/renderer/js/app.js index 272a82f2..dd7a3191 100644 --- a/emrg/gui/renderer/js/app.js +++ b/emrg/gui/renderer/js/app.js @@ -94,8 +94,7 @@ const App = (() => { return; } if (init.sessions && init.sessions.length > 0) { - state.sessions = init.sessions; - Sidebar.render(init.sessions); + state.sessions = init.sessions; // rant 11:44:52:历史会话列表已移除,不再渲染 conv-list // P4 slice 2:main 恢复的打开会话 + 激活会话(跳过 switchSession 的 IPC 往返) state.openSessions = init.open_sessions || []; Sidebar.renderOpenSessions(state.openSessions); @@ -651,7 +650,6 @@ const App = (() => { if (res.error === "session_not_found") { Chat.addSystemMessage(_t("app.deletedSwitch")); if (res.next_session) { - Sidebar.render(res.sessions || []); await switchSession(res.next_session, { silent: true }); } else { await newSession(); @@ -909,7 +907,6 @@ const App = (() => { try { const sessions = await window.emrg.listSessions(); state.sessions = sessions; - Sidebar.render(sessions); Sidebar.renderOpenSessions(state.openSessions); // 打开会话区 title 同步刷新 renderSessionHeader(state.sessionId); // 激活会话标题栏同步刷新 } catch { /* 忽略 */ } @@ -1491,7 +1488,6 @@ const App = (() => { break; case "sessions": state.sessions = data.sessions || []; - Sidebar.render(data.sessions || []); break; case "open_sessions": // P4 slice 2:main 广播打开会话列表变化 → 刷新侧边栏打开会话区 @@ -1539,7 +1535,6 @@ const App = (() => { case "list_result": if (data.type === "sessions_list") { state.sessions = data.sessions || []; - Sidebar.render(data.sessions || []); } break; case "command_result": diff --git a/emrg/gui/renderer/js/sidebar.js b/emrg/gui/renderer/js/sidebar.js index f6446e10..38d4638c 100644 --- a/emrg/gui/renderer/js/sidebar.js +++ b/emrg/gui/renderer/js/sidebar.js @@ -5,7 +5,6 @@ */ const Sidebar = (() => { - let sessions = []; let openSessions = []; /** @@ -46,45 +45,9 @@ const Sidebar = (() => { return title ? `${project}/${title}` : `${project}/${sid}`; } - /** cwd 末段作项目名(Path(s.cwd).name 语义,兼容 \\ 与 /) */ - function cwdProjectName(cwd) { - if (!cwd) return ""; - const norm = String(cwd).replace(/\\/g, "/").replace(/\/+$/, ""); - const seg = norm.split("/"); - return seg[seg.length - 1] || ""; - } - - /** 渲染会话列表(rant 17:48:07:去掉今天/昨天/更早分组,按最后活跃倒序,project/name|id) */ - function render(list) { - sessions = list || []; - const nav = $("conv-list"); - nav.innerHTML = ""; - if (!sessions.length) { - nav.appendChild(el("div", { class: "conv-item placeholder" }, EMRG_Copy.COPY.noSessions)); - return; - } - const sorted = [...sessions].sort((a, b) => - String(b.updated_at || b.created_at || "").localeCompare(String(a.updated_at || a.created_at || ""))); - for (const s of sorted) { - const item = el("div", { class: "conv-item" }); - item.dataset.sid = s.session_id; - const title = s.title || ""; // G27:title 优先,无 title 则空(id 已单独显示) - const project = cwdProjectName(s.cwd); - item.appendChild(el("span", { class: "conv-title" }, sessionLabel(project, title, s.session_id))); - item.addEventListener("click", () => App.switchSession(s.session_id, { scopeNav: nav })); - // 右键菜单:重命名 / 删除(友好确认) - item.addEventListener("contextmenu", (e) => { - e.preventDefault(); - App.showConvMenu(item, s.session_id, title || s.session_id); - }); - nav.appendChild(item); - } - highlight(App.state.sessionId); - } - - /** 高亮当前对话:指定 navEl 则仅更新该列表,否则两列表都更新(rant 2026-08-20T22:04:02 列表选中互不影响) */ + /** 高亮当前会话条目(rant 11:44:52:历史会话列表已移除,仅剩打开会话区) */ function highlight(sid, navEl) { - const targets = navEl ? [navEl] : [$("conv-list"), $("open-sessions")]; + const targets = navEl ? [navEl] : [$("open-sessions")]; for (const nav of targets) { if (!nav) continue; for (const item of nav.querySelectorAll(".conv-item")) { @@ -93,55 +56,7 @@ const Sidebar = (() => { } } - // ── 键盘导航:↑↓ 切换高亮 / Enter 切换会话(与 TUI /resume 选择器一致)── - let _keyHandler = null; - let _focusIdx = -1; - - function initKeyboard() { - const nav = $("conv-list"); - _keyHandler = (e) => { - // 输入控件(textarea/input/select/contenteditable)内不劫持 ↑↓/Enter—— - // 输入框是