6.2 KiB
Plan: 新增「会话」Tab(内嵌 webview)+ 进程清理改进
Context
当前「开始会话」会打开一个新的浏览器窗口,体验割裂。需要重构为在主窗口内新增「会话」Tab,内嵌 webview 展示会话页面,同时展示活跃会话列表,支持打开/停止。此外需要修复停止 agent 服务时僵尸进程的问题。
1. 新增 DetailedSession 类型
新建: src/shared/types/sessions.ts
export interface DetailedSession {
id: string;
title?: string;
engineType: 'claude-code' | 'qimingcode';
projectId?: string;
status: 'idle' | 'pending' | 'active' | 'terminating';
createdAt: number;
lastActivity?: number;
}
2. AcpEngine + UnifiedAgentService 新增方法
文件: src/main/services/engines/acp/acpEngine.ts
- 新增
listSessionsDetailed()— 遍历this.sessionsMap 返回 DetailedSession[](含 status/projectId/lastActivity + engineType fromthis.config.engine)
文件: src/main/services/engines/unifiedAgent.ts
- 新增
listAllSessionsDetailed()— 遍历this.enginesMap,汇总所有 engine 的 sessions
3. 新增 IPC handlers + Preload
文件: src/main/ipc/agentHandlers.ts
agent:listSessionsDetailed— 调用agentService.listAllSessionsDetailed()agent:stopSession— 根据 sessionId 定位 engine,先 abort 再 destroy 该 engine
文件: src/preload/index.ts
agent.listSessionsDetailedagent.stopSession
4. 新增 SessionsPage 组件(核心变更)
新建: src/renderer/components/pages/SessionsPage.tsx
布局设计
SessionsPage 内部有两个视图,通过 state 切换:
视图 A: 会话列表(默认)
- 顶部操作栏: 「新建会话」按钮 + 「刷新」按钮
- 活跃会话列表(Ant Design Table/List):
- 每行: 会话标题/ID、引擎类型 Tag、状态 Tag、创建时间
- 操作: 「打开」按钮(切换到视图 B 展示该会话 webview)、「停止」按钮(kill 进程)
- 每 3s 轮询
agent:listSessionsDetailed刷新 - 空状态提示
视图 B: 内嵌 webview
- 复用现有
EmbeddedWebview组件(src/renderer/components/EmbeddedWebview.tsx) - 工具栏「返回」按钮 → 切回视图 A
- URL 构造复用 ClientPage 中的 redirect URL 逻辑:
${domain}/api/sandbox/config/redirect/${userId} - Cookie 设置复用 ClientPage 中的 setCookie 逻辑
「新建会话」流程
点击「新建会话」→ 执行 cookie sync → 构造 redirect URL → 切换到视图 B(内嵌 webview 加载 URL)
「打开」已有会话流程
点击列表中「打开」→ 同样切换到视图 B,URL 可附带 session 参数(如果后端支持)或直接用 redirect URL
Props
SessionsPage 需要从 App.tsx 获取 auth 信息来构造 URL。两种方案:
- 方案 A(推荐): 组件内部通过
window.electronAPI.settings.get()读取 auth 信息(domain, userId, token),自包含 - 方案 B: 从 App.tsx 传 props
5. 重构 ClientPage「开始会话」
文件: src/renderer/components/pages/ClientPage.tsx
handleStartSession改为调用onNavigate('sessions')(已有此 prop)切换到会话 Tab- 删除
webview.openWindow相关逻辑 - 保留 QR 码功能不变
6. App.tsx 集成
文件: src/renderer/App.tsx
- TabKey 类型新增
'sessions' menuItems在'client'之后插入{ key: 'sessions', icon: <TeamOutlined />, label: '会话' }- 渲染区域新增
{activeTab === 'sessions' && <SessionsPage />} - import
SessionsPage和TeamOutlined
7. 进程清理改进(僵尸进程修复)
7a. 进程树 kill 工具
新建: src/main/services/utils/processTree.ts
export async function killProcessTree(pid: number, signal?: NodeJS.Signals): Promise<void>
- macOS/Linux: spawn 时
detached: true+process.kill(-pid, signal)杀进程组 - Windows:
taskkill /T /F /PID - 兜底: SIGTERM → 等 3s → SIGKILL
7b. AcpEngine.destroy() — SIGKILL 升级 + 进程树
文件: src/main/services/engines/acp/acpEngine.ts
改当前 this.acpProcess.kill() 为:
- 用
killProcessTree(pid, 'SIGTERM')杀进程树 - 等待最多 5s(监听
exit事件) - 超时后
killProcessTree(pid, 'SIGKILL')强杀
7c. AcpClient spawn — Unix 下 detached: true
文件: src/main/services/engines/acp/acpClient.ts
createAcpConnection spawn 时非 Windows 加 detached: true,支持进程组杀法。
7d. UnifiedAgentService.destroy() — 每个 engine 加超时
文件: src/main/services/engines/unifiedAgent.ts
每个 engine.destroy() 外包 Promise.race + 10s 超时。
7e. ManagedProcess.kill() — SIGKILL 升级
文件: src/main/processManager.ts
SIGTERM 后设 3s 定时器,进程未退出则 SIGKILL。
实施顺序
src/shared/types/sessions.ts— 新建 DetailedSession 类型src/main/services/utils/processTree.ts— 新建进程树 kill 工具src/main/services/engines/acp/acpClient.ts— spawn detached: true(Unix)src/main/services/engines/acp/acpEngine.ts— listSessionsDetailed() + destroy() 改进src/main/services/engines/unifiedAgent.ts— listAllSessionsDetailed() + destroy 超时src/main/processManager.ts— kill() SIGKILL 升级src/main/ipc/agentHandlers.ts— 新增 IPC handlerssrc/preload/index.ts— 暴露新 IPCsrc/renderer/components/pages/SessionsPage.tsx— 新建会话页面(列表 + 内嵌 webview)src/renderer/App.tsx— 新增 sessions tabsrc/renderer/components/pages/ClientPage.tsx— 重构「开始会话」为导航到 sessions tab
验证
npm run electron:dev启动应用- 登录后点击「开始会话」→ 确认跳转到「会话」tab 并在内嵌 webview 中打开(不再弹出新窗口)
- 「会话」tab 列表中可见活跃会话,状态正确
- 点击列表中「打开」→ 切到 webview 展示
- 点击「停止」→ 会话进程被终止,列表刷新
- 停止 agent 服务 → 所有引擎进程及子进程被清理,
ps aux | grep acp无僵尸 - webview 工具栏「返回」→ 回到列表视图