diff --git a/src/main/workspace.ts b/src/main/workspace.ts index e8974c6..55bd74a 100644 --- a/src/main/workspace.ts +++ b/src/main/workspace.ts @@ -61,15 +61,19 @@ export function startProcess( // 安全检查 const cmdCheck = checkCommandAllowed(command); if (!cmdCheck.ok) { + sendLog('warn', `🖥️ 命令被拦截`, `${command.slice(0, 100)} | ${cmdCheck.reason}`); return { success: false, error: cmdCheck.reason }; } const workDir = cwd ? path.resolve(cwd) : _workspaceDir; const dirCheck = checkPathAllowed(workDir, 'read'); if (!dirCheck.ok) { + sendLog('warn', `🖥️ 目录被拦截`, `${workDir} | ${dirCheck.reason}`); return { success: false, error: dirCheck.reason }; } + sendLog('info', `🖥️ spawn`, `ID: ${id} | ${command.slice(0, 100)} | cwd: ${workDir}`); + // 确保目录存在 if (!fs.existsSync(workDir)) { return { success: false, error: `工作目录不存在: ${workDir}` }; @@ -100,17 +104,20 @@ export function startProcess( proc.on('close', (code) => { activeProcesses.delete(id); + sendLog(code === 0 ? 'success' : 'warn', `🖥️ 进程退出`, `ID: ${id} | code: ${code}`); onExit(code); }); proc.on('error', (err) => { activeProcesses.delete(id); + sendLog('error', `🖥️ 进程启动失败`, `ID: ${id} | ${err.message}`); onOutput('stderr', `进程启动失败: ${err.message}\n`); onExit(1); }); return { success: true }; } catch (err) { + sendLog('error', `🖥️ spawn 异常`, `ID: ${id} | ${(err as Error).message}`); return { success: false, error: (err as Error).message }; } } @@ -118,13 +125,18 @@ export function startProcess( /** 停止指定进程 */ export function killProcess(id: string): boolean { const proc = activeProcesses.get(id); - if (!proc) return false; + if (!proc) { + sendLog('warn', `🖥️ kill 未找到进程`, `ID: ${id}`); + return false; + } try { proc.kill('SIGTERM'); activeProcesses.delete(id); + sendLog('info', `🖥️ 进程已终止`, `ID: ${id}`); return true; } catch { activeProcesses.delete(id); + sendLog('warn', `🖥️ kill 异常`, `ID: ${id}`); return false; } } diff --git a/src/renderer/components/workspace-panel.ts b/src/renderer/components/workspace-panel.ts index 389b88c..26c88f8 100644 --- a/src/renderer/components/workspace-panel.ts +++ b/src/renderer/components/workspace-panel.ts @@ -162,10 +162,12 @@ export async function initWorkspacePanel(): Promise { // 监听进程输出 bridge.workspace.onOutput((data) => { + logDebug('工作空间收到输出', `ID: ${data.id} | ${data.type} | ${data.data.length}字节`); appendTerminalOutput(data.id, data.type, data.data); }); bridge.workspace.onExit((data) => { + logDebug('工作空间收到退出', `ID: ${data.id} | code: ${data.code}`); handleProcessExit(data.id, data.code); }); @@ -323,10 +325,16 @@ function getActiveSession(): TerminalSession | undefined { function executeCommand(command: string): void { const session = getActiveSession(); - if (!session) return; + if (!session) { + logError('工作空间执行失败', '无活跃终端会话'); + return; + } const bridge = window.metonaDesktop; - if (!bridge?.isDesktop) return; + if (!bridge?.isDesktop) { + logError('工作空间执行失败', '非桌面环境'); + return; + } // 显示命令 session.lines.push({ type: 'system', text: `$ ${command}` }); @@ -336,13 +344,16 @@ function executeCommand(command: string): void { renderTerminal(); const cwd = currentFileDir || workspaceDir; + logInfo('工作空间执行命令', `ID: ${session.id} | ${command.slice(0, 100)} | cwd: ${cwd}`); bridge.workspace.exec({ id: session.id, command, cwd }); - logInfo('工作空间执行命令', command.slice(0, 100)); } function appendTerminalOutput(sessionId: string, type: 'stdout' | 'stderr', data: string): void { const session = terminalSessions.find(s => s.id === sessionId); - if (!session) return; + if (!session) { + logDebug('工作空间输出丢失', `未找到会话: ${sessionId}`); + return; + } // 按行分割,处理 \r 进度更新 const lines = data.split('\n'); @@ -375,11 +386,15 @@ function appendTerminalOutput(sessionId: string, type: 'stdout' | 'stderr', data function handleProcessExit(sessionId: string, code: number | null): void { const session = terminalSessions.find(s => s.id === sessionId); - if (!session) return; + if (!session) { + logDebug('工作空间退出信号丢失', `未找到会话: ${sessionId}`); + return; + } session.running = false; const exitMsg = code === 0 ? '✓ 进程正常退出' : `✗ 进程退出 (code: ${code})`; session.lines.push({ type: 'system', text: exitMsg }); + logInfo('工作空间进程退出', `ID: ${sessionId} | code: ${code}`); renderTerminal(); diff --git a/src/renderer/services/agent-engine.ts b/src/renderer/services/agent-engine.ts index bec0f6f..93f0e70 100644 --- a/src/renderer/services/agent-engine.ts +++ b/src/renderer/services/agent-engine.ts @@ -30,7 +30,8 @@ const TOOL_USAGE_GUIDE = `【工具使用规则】 1. 路径上下文:当用户说"修改这个文件"、"删除它"、"查看里面"等未指定路径时,必须从本次对话中最近的工具调用结果中提取路径。例如用户之前让你读取了 /home/user/project/config.json,后续说"修改配置"就应继续使用该路径,而不是推测新路径。 2. 工具调用结果中的 path 字段是权威的文件路径,优先使用它。 3. 如果对话中从未出现过相关路径,应先用 search_files 或 list_directory 定位,不要凭空猜测路径。 -4. 对同一文件的连续操作(读取→修改、读取→删除),路径必须一致。`; +4. 对同一文件的连续操作(读取→修改、读取→删除),路径必须一致。 +5. 当用户要求执行命令时,使用 run_command 工具执行。执行完成后,将 stdout/stderr 的结果告知用户。对于需要实时查看进度的长时间运行命令(如 npm install、ollama pull),建议用户在工作空间面板中手动执行。`; export interface AgentCallbacks { onThinking: (text: string) => void;