1- import { type Result , serializeResult } from '../../../lib' ;
1+ import { type Result , ValidationError , serializeResult } from '../../../lib' ;
22import { getErrorMessage } from '../../errors' ;
33import { withCommandRunTelemetry } from '../../telemetry/cli-command-run.js' ;
44import { AuthType , Protocol , standardize } from '../../telemetry/schemas/common-shapes.js' ;
55import { COMMAND_DESCRIPTIONS } from '../../tui/copy' ;
66import { requireProject , requireTTY } from '../../tui/guards' ;
77import { InvokeScreen } from '../../tui/screens/invoke' ;
88import { parseHeaderFlags } from '../shared/header-utils' ;
9- import { handleInvoke , loadInvokeConfig } from './action' ;
9+ import { type InvokeContext , handleInvoke , loadInvokeConfig } from './action' ;
1010import { resolvePrompt } from './resolve-prompt' ;
1111import type { InvokeOptions , InvokeResult } from './types' ;
1212import { validateInvokeOptions } from './validate' ;
@@ -36,16 +36,16 @@ function resolveProtocol(options: InvokeOptions, projectProtocol?: string): stri
3636 return 'http' ;
3737}
3838
39- async function handleInvokeCLI ( options : InvokeOptions ) : Promise < InvokeResult > {
39+ async function handleInvokeCLI ( options : InvokeOptions , preloadedContext ?: InvokeContext ) : Promise < InvokeResult > {
4040 const validation = validateInvokeOptions ( options ) ;
4141 if ( ! validation . valid ) {
42- return { success : false , error : new Error ( validation . error ) } ;
42+ return { success : false , error : new ValidationError ( validation . error ?? 'Validation failed' ) } ;
4343 }
4444
4545 let spinner : NodeJS . Timeout | undefined ;
4646
4747 try {
48- const context = await loadInvokeConfig ( ) ;
48+ const context = preloadedContext ?? ( await loadInvokeConfig ( ) ) ;
4949
5050 // Show spinner for non-streaming, non-json, non-exec invocations
5151 if ( ! options . stream && ! options . json && ! options . exec ) {
@@ -150,19 +150,14 @@ export const registerInvoke = (program: Command) => {
150150 try {
151151 requireProject ( ) ;
152152
153- // Parse custom headers
154- let headers : Record < string , string > | undefined ;
155- if ( cliOptions . header && cliOptions . header . length > 0 ) {
156- headers = parseHeaderFlags ( cliOptions . header ) ;
157- }
158-
159- // Determine protocol from project config (best-effort for telemetry)
153+ // Load config once for protocol resolution and to pass into handleInvokeCLI
154+ let invokeContext : InvokeContext | undefined ;
160155 let agentProtocol : string | undefined ;
161156 try {
162- const { project } = await loadInvokeConfig ( ) ;
157+ invokeContext = await loadInvokeConfig ( ) ;
163158 const agent = cliOptions . runtime
164- ? project . runtimes . find ( a => a . name === cliOptions . runtime )
165- : project . runtimes [ 0 ] ;
159+ ? invokeContext . project . runtimes . find ( a => a . name === cliOptions . runtime )
160+ : invokeContext . project . runtimes [ 0 ] ;
166161 agentProtocol = agent ?. protocol ;
167162 } catch {
168163 // Config load failure will be caught again inside handleInvokeCLI
@@ -189,44 +184,63 @@ export const registerInvoke = (program: Command) => {
189184 cliOptions . exec ||
190185 cliOptions . bearerToken
191186 ) {
192- const options : InvokeOptions = {
193- prompt : resolved . prompt ,
194- agentName : cliOptions . runtime ,
195- targetName : cliOptions . target ?? 'default' ,
196- sessionId : cliOptions . sessionId ,
197- userId : cliOptions . userId ,
198- json : cliOptions . json ,
199- stream : cliOptions . stream ,
200- tool : cliOptions . tool ,
201- input : cliOptions . input ,
202- exec : cliOptions . exec ,
203- timeout : cliOptions . timeout ,
204- headers,
205- bearerToken : cliOptions . bearerToken ,
206- } ;
207-
208187 const result = await withCommandRunTelemetry (
209188 'invoke' ,
210189 {
211- has_stream : options . stream ?? false ,
212- has_session_id : ! ! options . sessionId ,
213- auth_type : standardize ( AuthType , options . bearerToken ? 'bearer_token' : 'sigv4' ) ,
214- protocol : standardize ( Protocol , resolveProtocol ( options , agentProtocol ) ) ,
190+ has_stream : cliOptions . stream ?? false ,
191+ has_session_id : ! ! cliOptions . sessionId ,
192+ auth_type : standardize ( AuthType , cliOptions . bearerToken ? 'bearer_token' : 'sigv4' ) ,
193+ protocol : standardize (
194+ Protocol ,
195+ resolveProtocol ( { tool : cliOptions . tool } as InvokeOptions , agentProtocol )
196+ ) ,
215197 } ,
216198 async ( ) : Promise < InvokeResult > => {
217199 if ( ! resolved . success ) {
218- return { success : false , error : new Error ( resolved . error ?? 'Prompt resolution failed' ) } ;
200+ return { success : false , error : new ValidationError ( resolved . error ?? 'Prompt resolution failed' ) } ;
219201 }
220- return handleInvokeCLI ( options ) ;
202+
203+ // Parse custom headers inside wrapper so failures are recorded
204+ let headers : Record < string , string > | undefined ;
205+ if ( cliOptions . header && cliOptions . header . length > 0 ) {
206+ headers = parseHeaderFlags ( cliOptions . header ) ;
207+ }
208+
209+ const options : InvokeOptions = {
210+ prompt : resolved . prompt ,
211+ agentName : cliOptions . runtime ,
212+ targetName : cliOptions . target ?? 'default' ,
213+ sessionId : cliOptions . sessionId ,
214+ userId : cliOptions . userId ,
215+ json : cliOptions . json ,
216+ stream : cliOptions . stream ,
217+ tool : cliOptions . tool ,
218+ input : cliOptions . input ,
219+ exec : cliOptions . exec ,
220+ timeout : cliOptions . timeout ,
221+ headers,
222+ bearerToken : cliOptions . bearerToken ,
223+ } ;
224+
225+ return handleInvokeCLI ( options , invokeContext ) ;
221226 }
222227 ) ;
223228
224- printInvokeResult ( result , options ) ;
229+ printInvokeResult ( result , {
230+ json : cliOptions . json ,
231+ stream : cliOptions . stream ,
232+ } ) ;
225233 process . exit ( result . success ? 0 : 1 ) ;
226234 } else {
227235 // No CLI options - interactive TUI mode (headers still passed if provided)
228236 requireTTY ( ) ;
229237
238+ // Parse custom headers for TUI mode
239+ let headers : Record < string , string > | undefined ;
240+ if ( cliOptions . header && cliOptions . header . length > 0 ) {
241+ headers = parseHeaderFlags ( cliOptions . header ) ;
242+ }
243+
230244 const tuiResult = await withCommandRunTelemetry (
231245 'invoke' ,
232246 {
0 commit comments