diff --git a/apps/desktop/src/main/pi/agent-service.ts b/apps/desktop/src/main/pi/agent-service.ts index 44eeefe..90dd374 100644 --- a/apps/desktop/src/main/pi/agent-service.ts +++ b/apps/desktop/src/main/pi/agent-service.ts @@ -9,6 +9,7 @@ import { createAgentSessionFromServices, estimateTokens, getAgentDir, + getPowerShellConfig, SessionManager, type AgentSession, type AgentSessionEvent, @@ -53,7 +54,32 @@ const DELTA_FLUSH_MS = 40 const CUSTOM_TOOL_NAMES = new Set(browserToolNames) /** 需要人工审批的工具名单(高危内置工具;业务演示工具已随 demo-tools.ts 移除) */ -const TOOLS_REQUIRING_APPROVAL: ReadonlySet = new Set(['bash', 'write', 'edit']) +const TOOLS_REQUIRING_APPROVAL: ReadonlySet = new Set(['bash', 'powershell', 'write', 'edit']) + +/** Windows 优先 PowerShell:探测结果进程内缓存(getPowerShellConfig 会 spawnSync where 探测, + * 且平台与安装情况不会在应用运行中变化)。探测失败保持 bash(Git Bash)不动。 */ +let powershellProbe: boolean | null = null + +/** win32 且存在 pwsh/powershell 可执行文件时,把会话的默认 bash 工具换成 powershell, + * 模型的 shell 调用走原生 PowerShell 而非 Git Bash。幂等:无 bash 或已换过则原样返回。 + * 注意不能用 options.tools 传入(那会变成工具白名单,把插件注册的工具全部过滤掉), + * 也不能只传四个基础名调 setActiveToolsByName(那会把已激活的扩展工具一并挤掉), + * 所以按当前激活名单做替换。 */ +function preferPowerShell(session: AgentSession): void { + if (process.platform !== 'win32') return + if (powershellProbe === null) { + try { + getPowerShellConfig() + powershellProbe = true + } catch { + powershellProbe = false + } + } + if (!powershellProbe) return + const names = session.getActiveToolNames() + if (!names.includes('bash') || names.includes('powershell')) return + session.setActiveToolsByName(names.map((name) => (name === 'bash' ? 'powershell' : name))) +} /** * pi 会话运行时的主进程封装: @@ -294,6 +320,8 @@ export class AgentService { // 业务工具(browserTools 等)由插件经 pi.registerTool 注册(聚合 extension), // 此处不再传 customTools }) + // 会话创建是唯一收口点:新建/切换/分叉/重载都会经过这里,统一应用 Windows PowerShell 偏好 + preferPowerShell(result.session) return { ...result, services, diagnostics: services.diagnostics } } diff --git a/apps/desktop/src/renderer/src/components/ToolChips.tsx b/apps/desktop/src/renderer/src/components/ToolChips.tsx index 2972d3a..e6845cd 100644 --- a/apps/desktop/src/renderer/src/components/ToolChips.tsx +++ b/apps/desktop/src/renderer/src/components/ToolChips.tsx @@ -105,7 +105,7 @@ function extractResultText(result: unknown): string { function toolMeta(name: string): { icon: keyof typeof STEP_ICONS; label: string } { if (/^read|get|list|查|读|搜/i.test(name)) return { icon: 'read', label: '读取' } if (/^write|^edit|^multiedit|写|改|删|建|核/i.test(name)) return { icon: 'write', label: '编辑' } - if (/^bash|^shell|^terminal|终端/i.test(name)) return { icon: 'run', label: '终端' } + if (/^bash|^shell|^terminal|^powershell|终端/i.test(name)) return { icon: 'run', label: '终端' } if (/read|get|search|query|fetch|list|查|读|搜/i.test(name)) return { icon: 'read', label: '读取' } if (/write|edit|update|create|delete|patch|save|写|改|删|建|核/i.test(name)) return { icon: 'write', label: '编辑' } return { icon: 'run', label: name }