feat: 添加工作空间面板 - 右侧终端/文件浏览器

- 新增主进程 workspace.ts:spawn 进程管理,流式输出,安全检查
- IPC 双向通信:workspace:exec(on/send 模式,无超时限制)
- preload 暴露 workspace API
- 渲染进程 workspace-panel.ts:多终端 Tab、ANSI 颜色渲染、文件浏览器
- 设置面板添加工作空间目录配置
- 启动时自动创建 workspace 目录
- 窗口关闭时自动清理所有子进程
- 帮助文档更新
This commit is contained in:
thzxx
2026-04-07 18:30:45 +08:00
parent 9485b4c09e
commit 0e1f216aa4
10 changed files with 1555 additions and 0 deletions
+58
View File
@@ -17,6 +17,7 @@ import {
handleRunCommand
} from './tool-handlers.js';
import { getAllowedDirs, getBlockedDirs, setAllowedDirs } from './tool-security.js';
import { startProcess, killProcess, getWorkspaceDir, setWorkspaceDir, listWorkspaceDir } from './workspace.js';
export function setupIPC(): void {
ipcMain.handle('dialog:openFile', async (_, options?: { filters?: Array<{ name: string; extensions: string[] }> }) => {
@@ -108,4 +109,61 @@ export function setupIPC(): void {
ipcMain.handle('tool:setAllowedDirs', (_, dirs: string[]) => {
setAllowedDirs(dirs);
});
// ── Workspace IPC ──
// 获取工作空间目录
ipcMain.handle('workspace:getDir', () => {
return { dir: getWorkspaceDir(), defaultDir: getWorkspaceDir() };
});
// 设置工作空间目录
ipcMain.handle('workspace:setDir', (_, dir: string) => {
try {
setWorkspaceDir(dir);
return { success: true, dir: getWorkspaceDir() };
} catch (err) {
return { success: false, error: (err as Error).message };
}
});
// 列出工作空间目录
ipcMain.handle('workspace:listDir', (_, dirPath?: string) => {
return listWorkspaceDir(dirPath);
});
// 读取工作空间文件(复用 tool-handlers
ipcMain.handle('workspace:readFile', async (_, filePath: string) => {
return handleReadFile({ path: filePath });
});
// 启动命令(流式输出,通过 workspace:output 事件推送)
ipcMain.on('workspace:exec', (event, { id, command, cwd }: { id: string; command: string; cwd?: string }) => {
console.log('[IPC] workspace:exec', id, command.slice(0, 200));
const result = startProcess(
id,
command,
cwd,
(type, data) => {
// 流式推送输出到渲染进程
event.sender.send('workspace:output', { id, type, data });
},
(code) => {
// 通知进程结束
event.sender.send('workspace:exit', { id, code });
}
);
if (!result.success) {
event.sender.send('workspace:output', { id, type: 'stderr', data: result.error + '\n' });
event.sender.send('workspace:exit', { id, code: 1 });
}
});
// 停止命令
ipcMain.on('workspace:kill', (_, id: string) => {
console.log('[IPC] workspace:kill', id);
killProcess(id);
});
}