All files / shared toolFormatter.ts

98.82% Statements 84/85
72.32% Branches 115/159
100% Functions 2/2
98.8% Lines 83/84

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168                                                                                                            163x 30x 30x 30x 133x 7x 7x 7x 7x 7x 7x 126x 12x 12x 12x 12x 114x 8x 8x 8x 106x 1x 1x 105x 9x 9x 9x 96x 10x 10x 10x 10x 86x 8x 8x 8x 78x 16x 16x 62x 12x 12x 12x       50x 13x 37x 1x 36x 1x 1x 35x 14x 14x 14x 14x 14x 1x   14x 21x 1x 1x 1x 1x 1x     20x 1x 1x 1x 1x 1x 19x 1x 1x 1x 18x 1x 17x 1x 1x 1x 1x   16x     163x                                            
/**
 * Shared tool message formatting used by both the extension host
 * (for session restoration) and the webview (for real-time display).
 */
 
export interface ToolMessageData {
  role: 'tool'
  name: string
  summary: string
  toolUseId: string
  filePath?: string
  url?: string
  diff?: { oldString: string; newString: string } | { content: string }
  todos?: { content: string; status: string }[]
  skillArgs?: string
  agentPrompt?: string
  bashCommand?: string
  apiCall?: string
  result?: string | null
  isError?: boolean
  grepPattern?: string
  grepPath?: string
  grepGlob?: string
  globPattern?: string
  globPath?: string
  diffAutoOpened?: boolean
  problems?: {
    file: string
    problems: { severity: string; message: string; line: number; column: number; source?: string; code?: string }[]
  }[]
}
 
export function createToolMessage(name: string, toolUseId: string, input: Record<string, unknown>): ToolMessageData {
  let summary: string
  let filePath: string | undefined
  let url: string | undefined
  let diff: { oldString: string; newString: string } | { content: string } | undefined
  let bashCommand: string | undefined
  let apiCall: string | undefined
  let skillArgs: string | undefined
  let agentPrompt: string | undefined
  let todos: { content: string; status: string }[] | undefined
  let grepPattern: string | undefined
  let grepPath: string | undefined
  let grepGlob: string | undefined
  let globPattern: string | undefined
  let globPath: string | undefined
  let problems:
    | {
        file: string
        problems: { severity: string; message: string; line: number; column: number; source?: string; code?: string }[]
      }[]
    | undefined
 
  if (name === 'Bash') {
    const desc = input.description ? String(input.description) : null
    summary = desc ? `Bash: ${desc}` : 'Bash'
    bashCommand = input.command ? String(input.command) : undefined
  } else if (name === 'FileRead') {
    filePath = String(input.file_path ?? '') || undefined
    const filename = filePath?.split('/').pop() ?? filePath ?? ''
    const offset = input.offset != null ? Number(input.offset) + 1 : 1
    const limit = input.limit != null ? Number(input.limit) : null
    const range = limit != null ? `lines ${offset}–${offset + limit - 1}` : `line ${offset}+`
    summary = `Read ${filename} (${range})`
  } else if (name === 'Edit' || name === 'FileEdit') {
    filePath = String(input.file_path ?? '') || undefined
    const filename = filePath?.split('/').pop() ?? filePath ?? ''
    summary = `Edit ${filename}`
    diff = { oldString: String(input.old_string ?? ''), newString: String(input.new_string ?? '') }
  } else if (name === 'Write' || name === 'FileWrite') {
    filePath = String(input.file_path ?? '') || undefined
    const filename = filePath?.split('/').pop() ?? filePath ?? ''
    summary = `Write ${filename}`
  } else if (name === 'Skill') {
    summary = `Skill: ${String(input.skill ?? 'unknown')}`
    skillArgs = input.args ? String(input.args) : undefined
  } else if (name === 'Glob') {
    globPattern = String(input.pattern ?? '')
    globPath = input.path ? String(input.path) : undefined
    summary = `Glob: ${globPattern}`
  } else if (name === 'Grep') {
    grepPattern = String(input.pattern ?? '')
    grepPath = input.path ? String(input.path) : undefined
    grepGlob = input.glob ? String(input.glob) : undefined
    summary = `Grep: ${grepPattern}`
  } else if (name === 'WebFetch') {
    url = String(input.url ?? '')
    const hostname = url ? new URL(url).hostname : ''
    summary = `Fetch ${hostname}`
  } else if (name === 'AskUserQuestion') {
    const qs = (input.questions as { question?: string }[] | undefined) ?? []
    summary = `AskUserQuestion (${qs.length} question${qs.length === 1 ? '' : 's'})`
  } else if (name === 'TodoWrite') {
    const todoList = (input.todos as { content?: string; status?: string }[] | undefined) ?? []
    summary = `TodoWrite (${todoList.length} task${todoList.length === 1 ? '' : 's'})`
    todos = todoList.map((t) => ({
      content: t.content ?? '',
      status: t.status ?? 'pending',
    }))
  } else if (name === 'EnterPlanMode') {
    summary = 'Entering Plan Mode'
  } else if (name === 'ExitPlanMode') {
    summary = 'Exiting Plan Mode'
  } else if (name === 'mcp__ide-vs-code__build_app' || name === 'build_app') {
    const appName = input.appName ? String(input.appName) : null
    summary = appName ? `Build App: ${appName}` : 'Build App'
  } else if (name === 'mcp__ide-vs-code__call_bzapi' || name === 'call_bzapi') {
    const method = String(input.method ?? 'GET')
    const service = String(input.service ?? '')
    const apiPath = String(input.path ?? '')
    apiCall = `${method} ${service}${apiPath}`
    if (input.body) {
      apiCall += `\n${JSON.stringify(input.body, null, 2).slice(0, 300)}`
    }
    summary = `API: ${service}`
  } else if (name === 'mcp__ide-vs-code__call_anksy_route' || name === 'call_anksy_route') {
    const method = String(input.method ?? 'GET')
    const routePath = String(input.path ?? '')
    summary = `Call My App API: ${method} ${routePath}`
    apiCall = `${method} ${routePath}`
    Iif (input.body) {
      apiCall += `\n\nBody:\n${JSON.stringify(input.body, null, 2)}`
    }
  } else if (name === 'mcp__ide-vs-code__get_bzapi_spec' || name === 'get_bzapi_spec') {
    const apiName = String(input.name ?? '')
    const paths = (input.paths as string[] | undefined)?.join(', ') ?? ''
    const schemas = input.include_schemas ? ' (+schemas)' : ''
    apiCall = paths ? `${apiName}: ${paths}${schemas}` : `${apiName} (overview)`
    summary = `API Spec: ${apiName}`
  } else if (name === 'Agent') {
    const desc = input.description ? String(input.description) : ''
    summary = desc ? `Sub-agent: ${desc}` : 'Sub-agent'
    agentPrompt = input.prompt ? String(input.prompt) : undefined
  } else if (name === 'mcp__ide-vs-code__new_app_from_template' || name === 'new_app_from_template') {
    summary = 'New App from Template'
  } else if (name === 'mcp__ide-vs-code__get_problems' || name === 'get_problems') {
    const severity = input.severity ? String(input.severity) : 'all'
    const filterPath = input.filePath ? String(input.filePath) : null
    const filter = filterPath ? ` (${filterPath})` : ''
    summary = `Get Problems: ${severity}${filter}`
  } else {
    summary = `${name}(${JSON.stringify(input).slice(0, 120)})`
  }
 
  return {
    role: 'tool',
    name,
    summary,
    toolUseId,
    filePath,
    url,
    diff,
    todos,
    skillArgs,
    agentPrompt,
    bashCommand,
    apiCall,
    grepPattern,
    grepPath,
    grepGlob,
    globPattern,
    globPath,
    problems,
    result: null,
  }
}