MCPcopy Index your code
hub / github.com/claude-code-best/claude-code / normalizeToolInput

Function normalizeToolInput

src/utils/api.ts:577–692  ·  view source on GitHub ↗
(
  tool: T,
  input: z.infer<T['inputSchema']>,
  agentId?: AgentId,
)

Source from the content-addressed store, hash-verified

575
576// TODO: Generalize this to all tools
577export function normalizeToolInput<T extends Tool>(
578 tool: T,
579 input: z.infer<T['inputSchema']>,
580 agentId?: AgentId,
581): z.infer<T['inputSchema']> {
582 switch (tool.name) {
583 case EXIT_PLAN_MODE_V2_TOOL_NAME: {
584 // Always inject plan content and file path for ExitPlanModeV2 so hooks/SDK get the plan.
585 // The V2 tool reads plan from file instead of input, but hooks/SDK
586 const plan = getPlan(agentId)
587 const planFilePath = getPlanFilePath(agentId)
588 // Persist file snapshot for CCR sessions so the plan survives pod recycling
589 void persistFileSnapshotIfRemote()
590 return plan !== null ? { ...input, plan, planFilePath } : input
591 }
592 case BashTool.name: {
593 // Validated upstream, won't throw
594 const parsed = BashTool.inputSchema.parse(input)
595 const { command, timeout, description } = parsed
596 const cwd = getCwd()
597 let normalizedCommand = command.replace(`cd ${cwd} && `, '')
598 if (getPlatform() === 'windows') {
599 normalizedCommand = normalizedCommand.replace(
600 `cd ${windowsPathToPosixPath(cwd)} && `,
601 '',
602 )
603 }
604
605 // Replace \\; with \; (commonly needed for find -exec commands)
606 normalizedCommand = normalizedCommand.replace(/\\\\;/g, '\\;')
607
608 // Logging for commands that are only echoing a string. This is to help us understand how often Claude talks via bash
609 if (/^echo\s+["']?[^|&;><]*["']?$/i.test(normalizedCommand.trim())) {
610 logEvent('tengu_bash_tool_simple_echo', {})
611 }
612
613 // Check for run_in_background (may not exist in schema if CLAUDE_CODE_DISABLE_BACKGROUND_TASKS is set)
614 const run_in_background =
615 'run_in_background' in parsed ? parsed.run_in_background : undefined
616
617 // SAFETY: Cast is safe because input was validated by .parse() above.
618 // TypeScript can't narrow the generic T based on switch(tool.name), so it
619 // doesn't know the return type matches T['inputSchema']. This is a fundamental
620 // TS limitation with generics, not bypassable without major refactoring.
621 return {
622 command: normalizedCommand,
623 description,
624 ...(timeout !== undefined && { timeout }),
625 ...(description !== undefined && { description }),
626 ...(run_in_background !== undefined && { run_in_background }),
627 ...('dangerouslyDisableSandbox' in parsed &&
628 parsed.dangerouslyDisableSandbox !== undefined && {
629 dangerouslyDisableSandbox: parsed.dangerouslyDisableSandbox,
630 }),
631 } as z.infer<T['inputSchema']>
632 }
633 case FileEditTool.name: {
634 // Validated upstream, won't throw

Callers 1

normalizeContentFromAPIFunction · 0.85

Calls 8

getPlanFunction · 0.85
getPlanFilePathFunction · 0.85
getCwdFunction · 0.85
getPlatformFunction · 0.85
logEventFunction · 0.85
normalizeFileEditInputFunction · 0.85
stripTrailingWhitespaceFunction · 0.85

Tested by

no test coverage detected