@@ -21,6 +21,9 @@ $ErrorActionPreference = 'Stop'
2121. PARAMETER Prompt
2222 原始 prompt 文本,仅用于统计长度,不在预览中明文打印。
2323
24+ . PARAMETER InputText
25+ 需要写入外部命令 stdin 的文本。
26+
2427. PARAMETER UnsupportedOptions
2528 当前 agent 不支持的统一配置字段。
2629
@@ -41,6 +44,8 @@ function New-AiAgentCommandSpec {
4144
4245 [string ]$Prompt = ' ' ,
4346
47+ [string ]$InputText = ' ' ,
48+
4449 [string []]$UnsupportedOptions = @ ()
4550 )
4651
@@ -49,6 +54,7 @@ function New-AiAgentCommandSpec {
4954 ArgumentList = @ ($ArgumentList )
5055 WorkingDirectory = $WorkingDirectory
5156 Prompt = $Prompt
57+ InputText = $InputText
5258 UnsupportedOptions = @ ($UnsupportedOptions )
5359 }
5460}
@@ -80,6 +86,9 @@ function Format-AiAgentCommandPreview {
8086 if ($arg -eq $prompt -and -not [string ]::IsNullOrEmpty($prompt )) {
8187 $parts.Add (' <PROMPT>' ) | Out-Null
8288 }
89+ elseif ($arg -eq ' -' -and -not [string ]::IsNullOrEmpty([string ]$Spec.InputText )) {
90+ $parts.Add (' <PROMPT_STDIN>' ) | Out-Null
91+ }
8392 else {
8493 $parts.Add ([string ]$arg ) | Out-Null
8594 }
@@ -88,6 +97,97 @@ function Format-AiAgentCommandPreview {
8897 return (" {0} {1}`n WorkDir={2}`n PromptChars={3}" -f $Spec.FilePath , ($parts -join ' ' ), $Spec.WorkingDirectory , $prompt.Length )
8998}
9099
100+ <#
101+ . SYNOPSIS
102+ 解析真实调用的 agent CLI 路径。
103+
104+ . DESCRIPTION
105+ Windows 上 npm 等工具常同时生成 `.ps1` 与 `.cmd` 包装器。PowerShell 脚本再次调用 `.ps1`
106+ 包装器时,可能把标准流识别成非终端并触发 agent 的 TTY 检查错误;因此执行前优先选择
107+ `.cmd`、`.exe`、`.bat` 形式的应用包装器。预览仍保留原始命令名,避免泄露本机安装路径。
108+
109+ . PARAMETER FilePath
110+ 命令规格中的外部 CLI 名称或路径。
111+
112+ . OUTPUTS
113+ string
114+ 返回实际用于 `&` 调用的命令路径或名称。
115+ #>
116+ function Resolve-AiAgentInvocationFilePath {
117+ [CmdletBinding ()]
118+ param (
119+ [Parameter (Mandatory )]
120+ [string ]$FilePath
121+ )
122+
123+ $runsOnWindows = [System.Runtime.InteropServices.RuntimeInformation ]::IsOSPlatform(
124+ [System.Runtime.InteropServices.OSPlatform ]::Windows
125+ )
126+ if (-not $runsOnWindows ) {
127+ return $FilePath
128+ }
129+
130+ if ([System.IO.Path ]::IsPathRooted($FilePath ) -or -not [string ]::IsNullOrWhiteSpace([System.IO.Path ]::GetExtension($FilePath ))) {
131+ return $FilePath
132+ }
133+
134+ foreach ($extension in @ (' .cmd' , ' .exe' , ' .bat' )) {
135+ $candidate = Get-Command - Name " $FilePath$extension " - CommandType Application - ErrorAction SilentlyContinue |
136+ Select-Object - First 1
137+ if ($null -ne $candidate ) {
138+ return $candidate.Source
139+ }
140+ }
141+
142+ return $FilePath
143+ }
144+
145+ <#
146+ . SYNOPSIS
147+ 执行外部 agent 命令并转发输出。
148+
149+ . DESCRIPTION
150+ PowerShell 函数会把外部命令 stdout 合并到自身成功输出流。runner 顶层需要用函数返回对象读取
151+ ExitCode,因此这里把 stdout 写到 host,避免 agent 日志污染结构化返回值。
152+
153+ . PARAMETER FilePath
154+ 实际调用的外部 CLI 路径或名称。
155+
156+ . PARAMETER ArgumentList
157+ 传递给外部 CLI 的参数数组。
158+
159+ . PARAMETER InputText
160+ 需要写入外部命令 stdin 的文本。为空时不主动写入 stdin。
161+
162+ . OUTPUTS
163+ int
164+ 返回外部命令的退出码。
165+ #>
166+ function Invoke-AiAgentNativeCommand {
167+ [CmdletBinding ()]
168+ param (
169+ [Parameter (Mandatory )]
170+ [string ]$FilePath ,
171+
172+ [string []]$ArgumentList = @ (),
173+
174+ [string ]$InputText = ' '
175+ )
176+
177+ if ([string ]::IsNullOrEmpty($InputText )) {
178+ & $FilePath @ArgumentList | ForEach-Object {
179+ Write-Host $_
180+ }
181+ }
182+ else {
183+ $InputText | & $FilePath @ArgumentList | ForEach-Object {
184+ Write-Host $_
185+ }
186+ }
187+
188+ return $LASTEXITCODE
189+ }
190+
91191<#
92192. SYNOPSIS
93193 检查外部 agent CLI 是否可用。
@@ -109,7 +209,7 @@ function Assert-AiAgentCommandAvailable {
109209 [string ]$FilePath
110210 )
111211
112- if (-not (Get-Command - Name $FilePath - ErrorAction SilentlyContinue)) {
212+ if (-not (Test-Path - LiteralPath $FilePath - PathType Leaf) -and -not ( Get-Command - Name $FilePath - ErrorAction SilentlyContinue)) {
113213 throw " 未找到 $FilePath ,请先安装并完成登录。"
114214 }
115215}
0 commit comments