* Parse elicitation-specific fields from a HookOutsideReplResult. * Mirrors the relevant branches of processHookJSONOutput for Elicitation * and ElicitationResult hook events.
( result: HookOutsideReplResult, expectedEventName: 'Elicitation' | 'ElicitationResult', )
| 4545 | * and ElicitationResult hook events. |
| 4546 | */ |
| 4547 | function parseElicitationHookOutput( |
| 4548 | result: HookOutsideReplResult, |
| 4549 | expectedEventName: 'Elicitation' | 'ElicitationResult', |
| 4550 | ): { |
| 4551 | response?: ElicitationResponse |
| 4552 | blockingError?: HookBlockingError |
| 4553 | } { |
| 4554 | // Exit code 2 = blocking (same as executeHooks path) |
| 4555 | if (result.blocked && !result.succeeded) { |
| 4556 | return { |
| 4557 | blockingError: { |
| 4558 | blockingError: result.output || `Elicitation blocked by hook`, |
| 4559 | command: result.command, |
| 4560 | }, |
| 4561 | } |
| 4562 | } |
| 4563 | |
| 4564 | if (!result.output.trim()) { |
| 4565 | return {} |
| 4566 | } |
| 4567 | |
| 4568 | // Try to parse JSON output for structured elicitation response |
| 4569 | const trimmed = result.output.trim() |
| 4570 | if (!trimmed.startsWith('{')) { |
| 4571 | return {} |
| 4572 | } |
| 4573 | |
| 4574 | try { |
| 4575 | const parsed = hookJSONOutputSchema().parse(JSON.parse(trimmed)) |
| 4576 | if (isAsyncHookJSONOutput(parsed)) { |
| 4577 | return {} |
| 4578 | } |
| 4579 | if (!isSyncHookJSONOutput(parsed)) { |
| 4580 | return {} |
| 4581 | } |
| 4582 | |
| 4583 | // Cast to typed interface for type-safe property access |
| 4584 | const typedParsed = parsed as TypedSyncHookOutput |
| 4585 | |
| 4586 | // Check for top-level decision: 'block' (exit code 0 + JSON block) |
| 4587 | if (typedParsed.decision === 'block' || result.blocked) { |
| 4588 | return { |
| 4589 | blockingError: { |
| 4590 | blockingError: typedParsed.reason || 'Elicitation blocked by hook', |
| 4591 | command: result.command, |
| 4592 | }, |
| 4593 | } |
| 4594 | } |
| 4595 | |
| 4596 | const specific = typedParsed.hookSpecificOutput |
| 4597 | if (!specific || specific.hookEventName !== expectedEventName) { |
| 4598 | return {} |
| 4599 | } |
| 4600 | |
| 4601 | if (!('action' in specific) || !(specific as { action?: string }).action) { |
| 4602 | return {} |
| 4603 | } |
| 4604 |
no test coverage detected