diff --git a/Agent.md b/Agent.md index a9c00225..37aa1ea2 100644 --- a/Agent.md +++ b/Agent.md @@ -121,7 +121,7 @@ pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.token; python -m emrg Python: `uv run pytest tests/ -v` (1123) — import check: `uv run python -c "from emrg.client.app import run_client"` GUI: `cd emrg/gui && npm test` (89: 45 daemon_client + 20 conn-manager + 8 integration + 6 build-config + 7 gui-state + 3 preload-api) — syntax: `node --check main.js preload.js daemon_client.js` -Renderer: `cd emrg/gui/renderer && npm run typecheck && npm test` (441: 5 snapshot-store + 9 utils + 3 ErrorBoundary + 2 App smoke + 11 commands + 4 copywriting + 11 i18n + 11 markdown + 15 transcript + 7 TranscriptView + 15 history + 22 composer + 14 Composer + 12 sidebar + 17 Sidebar + 9 fileTree + 9 FileTree + 16 resultPanel + 8 ResultPanel + 29 workspaceView + 8 WorkspaceView + 10 dialog + 6 Dialog + 9 ConfirmDialog + 9 RenameDialog + 10 dialogLists + 3 HelpDialog + 9 MemoryDialog + 6 SkillsDialog + 9 openSession + 6 WelcomeDialog + 8 OpenSessionDialog + 7 NewSessionDialog + 7 rewind + 8 RewindDialog + 7 GithubDeviceDialog + 12 daemonBridge + 6 DaemonBridgeProvider + 23 Shell + 15 DialogHost + 19 SettingsPanel + 6 TaskFormDialog + 5 RantDialog + 4 vendorMarkdown) + `npm run build` → `renderer/dist/` +Renderer: `cd emrg/gui/renderer && npm run typecheck && npm test` (442: 5 snapshot-store + 9 utils + 3 ErrorBoundary + 2 App smoke + 11 commands + 4 copywriting + 11 i18n + 11 markdown + 15 transcript + 7 TranscriptView + 15 history + 22 composer + 14 Composer + 12 sidebar + 17 Sidebar + 9 fileTree + 9 FileTree + 16 resultPanel + 8 ResultPanel + 29 workspaceView + 8 WorkspaceView + 10 dialog + 6 Dialog + 9 ConfirmDialog + 9 RenameDialog + 10 dialogLists + 3 HelpDialog + 9 MemoryDialog + 6 SkillsDialog + 9 openSession + 6 WelcomeDialog + 8 OpenSessionDialog + 7 NewSessionDialog + 7 rewind + 8 RewindDialog + 7 GithubDeviceDialog + 12 daemonBridge + 6 DaemonBridgeProvider + 24 Shell + 15 DialogHost + 19 SettingsPanel + 6 TaskFormDialog + 5 RantDialog + 4 vendorMarkdown) + `npm run build` → `renderer/dist/` 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 路径不受影响) Git-over-https 兜底: `python scripts/sync-master-from-api.py [--repo owner/name] [--ref master]` — 受限网络下 github.com:443 不可达而 api.github.com 可达时,用 Git Data API 的 verification payload + signature 字节级重建上游 commit(含 web-flow GPG 签名 squash merge,reconstruct_commit 经 hermetic 测试验证 sha 一致)并推进本地 refs;内容对象缺失时 fail-loud 提示改用 git fetch(10+ 周期实证的恢复路径) diff --git a/emrg/gui/renderer/src/components/Shell.test.tsx b/emrg/gui/renderer/src/components/Shell.test.tsx index 24affa82..91275120 100644 --- a/emrg/gui/renderer/src/components/Shell.test.tsx +++ b/emrg/gui/renderer/src/components/Shell.test.tsx @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { act, fireEvent, render, screen, waitFor } from "@testing-library/react"; import type { ReactNode } from "react"; import { Shell } from "./Shell"; import { DaemonBridgeProvider } from "./DaemonBridgeProvider"; @@ -322,6 +322,29 @@ describe("Shell (Batch 5 slice 3 chat wiring)", () => { // ── Batch 5 slice 8:任务表单 + Rant 对话框接线 ── + it("任务面板激活时每 5s 轮询 listTasks(vanilla startTaskPoll 语义)", async () => { + vi.useFakeTimers(); + try { + const m = mockEmrg(); + render(wrapper()); + await vi.waitFor(() => expect(screen.getByTestId("composer")).toBeInTheDocument()); + fireEvent.click(screen.getByTestId("nav-tasks")); + await vi.waitFor(() => expect(screen.getByTestId("task-row")).toBeInTheDocument()); + const callsAfterActivation = m.listTasks.mock.calls.length; + expect(callsAfterActivation).toBeGreaterThanOrEqual(1); + // 快进 5s → 再次轮询;再快进 10s → 至少再两次 + await act(async () => { + vi.advanceTimersByTime(5000); + }); + await act(async () => { + vi.advanceTimersByTime(10_000); + }); + expect(m.listTasks.mock.calls.length).toBeGreaterThanOrEqual(callsAfterActivation + 2); + } finally { + vi.useRealTimers(); + } + }); + it("任务面板「+ 添加任务」→ 打开表单 → 保存 → taskCreate + 刷新列表", async () => { const m = mockEmrg(); render(wrapper()); diff --git a/emrg/gui/renderer/src/components/Shell.tsx b/emrg/gui/renderer/src/components/Shell.tsx index cc5f71cf..dec130e2 100644 --- a/emrg/gui/renderer/src/components/Shell.tsx +++ b/emrg/gui/renderer/src/components/Shell.tsx @@ -145,6 +145,18 @@ export function Shell() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [activeView]); + // 任务面板激活时每 5s 轮询任务状态(vanilla startTaskPoll,rant 2026-08-22T07:18:35 方案 B: + // 宿主确认轮询、可接受几秒滞后)——让"运行中→待运行"切换与下次倒计时 ≤5s 内自动更新, + // 不引入事件推送。幂等:重复启动先清旧定时器;离开任务视图清除防泄漏;轮询失败静默下轮重试。 + useEffect(() => { + if (activeView !== "tasks") return; + const id = setInterval(() => { + void loadTasks(); + }, 5000); + return () => clearInterval(id); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [activeView]); + // ── workspace 面板动作(vanilla dialogs.js 语义) ── async function addProject() { const b = wsBridge();