(name: string, arg: string, full = false)
| 181 | * collapsed header passes the default (clipped) form. |
| 182 | */ |
| 183 | export function toolSummary(name: string, arg: string, full = false): string { |
| 184 | // Local clip that becomes a no-op (trim only) in `full` mode. |
| 185 | const c = (s: string, max = SUMMARY_MAX): string => (full ? s.trim() : clip(s, max)); |
| 186 | try { |
| 187 | const d = parseArg(arg); |
| 188 | // Empty argument (e.g. `{}`): keep it OUT of the collapsed header title, but |
| 189 | // still show it in the expanded body (full mode) so the detail isn't lost. |
| 190 | if (!full && isEmptyArg(arg, d)) return ''; |
| 191 | // Plain-string arg (already a human string). |
| 192 | const fallback = () => c(arg.replace(/^·\s*/, '')); |
| 193 | if (!d) return fallback(); |
| 194 | |
| 195 | switch (normalizeToolName(name)) { |
| 196 | case 'read': { |
| 197 | const path = filePath(d); |
| 198 | if (!path) return fallback(); |
| 199 | const start = num(d.offset) ?? num(d.line_start) ?? num(d.start_line); |
| 200 | const len = num(d.limit) ?? num(d.length); |
| 201 | const end = num(d.line_end) ?? num(d.end_line) ?? (start !== undefined && len !== undefined ? start + len : undefined); |
| 202 | if (start !== undefined && end !== undefined) return c(`${path}:${start}-${end}`); |
| 203 | if (start !== undefined) return c(`${path}:${start}`); |
| 204 | return c(path); |
| 205 | } |
| 206 | case 'write': { |
| 207 | const path = filePath(d); |
| 208 | return path ? c(`${path} ${t('tools.chip.created')}`) : fallback(); |
| 209 | } |
| 210 | case 'edit': |
| 211 | case 'multi_edit': { |
| 212 | const path = filePath(d); |
| 213 | return path ? c(path) : fallback(); |
| 214 | } |
| 215 | case 'bash': { |
| 216 | const cmd = str(d.command) ?? str(d.cmd) ?? str(d.script); |
| 217 | return cmd ? c(cmd, BASH_MAX) : fallback(); |
| 218 | } |
| 219 | case 'grep': |
| 220 | case 'search': { |
| 221 | const pattern = str(d.pattern) ?? str(d.query) ?? str(d.regex); |
| 222 | const path = str(d.path) ?? str(d.glob) ?? str(d.include); |
| 223 | if (pattern && path) return c(`${pattern} in ${path}`); |
| 224 | return pattern ? c(pattern) : fallback(); |
| 225 | } |
| 226 | case 'glob': { |
| 227 | const pattern = str(d.pattern) ?? str(d.glob) ?? str(d.query); |
| 228 | const path = str(d.path) ?? str(d.cwd); |
| 229 | if (pattern && path) return c(`${pattern} in ${path}`); |
| 230 | return pattern ? c(pattern) : (str(d.path) ? c(str(d.path)!) : fallback()); |
| 231 | } |
| 232 | case 'ls': { |
| 233 | const dir = str(d.path) ?? str(d.dir) ?? str(d.directory) ?? str(d.cwd); |
| 234 | return dir ? c(dir) : fallback(); |
| 235 | } |
| 236 | case 'web_fetch': { |
| 237 | const url = str(d.url) ?? str(d.uri); |
| 238 | return url ? c(urlHost(url)) : fallback(); |
| 239 | } |
| 240 | case 'todo': |
no test coverage detected