(input: unknown)
| 132 | * Same duck-type strategy as toolResultSearchText — known field names, |
| 133 | * unknown → empty. Under-count > phantom. */ |
| 134 | export function toolUseSearchText(input: unknown): string { |
| 135 | if (!input || typeof input !== 'object') return '' |
| 136 | const o = input as Record<string, unknown> |
| 137 | const parts: string[] = [] |
| 138 | // renderToolUseMessage typically shows one or two of these as the |
| 139 | // primary argument. tool_name itself is in the "⏺ Bash(...)" chrome, |
| 140 | // handled by under-count (the overlay matches it but we don't count it). |
| 141 | for (const k of [ |
| 142 | 'command', |
| 143 | 'pattern', |
| 144 | 'file_path', |
| 145 | 'path', |
| 146 | 'prompt', |
| 147 | 'description', |
| 148 | 'query', |
| 149 | 'url', |
| 150 | 'skill', // SkillTool |
| 151 | ]) { |
| 152 | const v = o[k] |
| 153 | if (typeof v === 'string') parts.push(v) |
| 154 | } |
| 155 | // args[] (Tmux/TungstenTool), files[] (SendUserFile) — tool-use |
| 156 | // renders the joined array as the primary display. Under-count > skip. |
| 157 | for (const k of ['args', 'files']) { |
| 158 | const v = o[k] |
| 159 | if (Array.isArray(v) && v.every(x => typeof x === 'string')) { |
| 160 | parts.push((v as string[]).join(' ')) |
| 161 | } |
| 162 | } |
| 163 | return parts.join('\n') |
| 164 | } |
| 165 | |
| 166 | /** Duck-type the tool's native Out for searchable text. Known shapes: |
| 167 | * {stdout,stderr} (Bash/Shell), {content} (Grep), {file:{content}} (Read), |
no test coverage detected