import { randomUUID } from "node:crypto"; import { TextResult } from "../types"; // eslint-disable-next-line @typescript-eslint/no-explicit-any export function logged( name: string, handler: (...args: A) => Promise, ): (...args: A) => Promise { return async (...args: A) => { const id = randomUUID().slice(0, 8); const t0 = process.hrtime.bigint(); console.log(`[tool>] ${name} #${id} args=${JSON.stringify(args)}`); try { const result = await handler(...args); const ms = Number(process.hrtime.bigint() - t0) / 1e6; console.log( `[tool<] ${name} #${id} ${ms.toFixed(1)}ms` + `${result.isError ? " ERROR" : ""} result=${JSON.stringify(result).slice(0, 2000)}`, ); return result; } catch (err) { const ms = Number(process.hrtime.bigint() - t0) / 1e6; console.error(`[tool!] ${name} #${id} ${ms.toFixed(1)}ms threw:`, err); throw err; // let the SDK turn it into a JSON-RPC error } }; } export function isValidHost(host: string): boolean { // allow IPv4, IPv6, and hostnames; reject anything with shell metacharacters return /^[a-zA-Z0-9.:_-]+$/.test(host) && host.length <= 255; }