64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
import { parametersSchema as z, defineCustomTool, CustomToolContext } from "@roo-code/types"
|
|
// @ts-ignore - Node built-ins
|
|
import { spawnSync } from "child_process"
|
|
|
|
export default defineCustomTool({
|
|
name: "port_watch",
|
|
description: "Check what process holds a given TCP/UDP port. Replaces 'lsof -i :PORT' shell calls when debugging dev servers.",
|
|
parameters: z.object({
|
|
port: z.number().describe("TCP port number to check (1-65535)"),
|
|
protocol: z.enum(["tcp", "udp", "both"]).optional().describe("Protocol filter (default: tcp)"),
|
|
}),
|
|
async execute({ port, protocol = "tcp" }, context: CustomToolContext) {
|
|
try {
|
|
if (port < 1 || port > 65535) {
|
|
return JSON.stringify({ error: "Invalid port: must be between 1 and 65535" }, null, 2)
|
|
}
|
|
|
|
const listeners: any[] = []
|
|
|
|
const runLsof = (proto: string) => {
|
|
const flag = proto === "tcp" ? `-iTCP:${port}` : `-iUDP:${port}`
|
|
const stateFlag = proto === "tcp" ? ["-sTCP:LISTEN"] : []
|
|
const result = spawnSync("lsof", [flag, ...stateFlag, "-P", "-n"], {
|
|
encoding: "utf-8",
|
|
timeout: 10_000,
|
|
})
|
|
|
|
if (!result.stdout) return
|
|
|
|
const lines = result.stdout.split("\n").filter((l: string) => l.trim())
|
|
// Skip header line
|
|
for (let i = 1; i < lines.length; i++) {
|
|
const parts = lines[i].split(/\s+/)
|
|
if (parts.length < 9) continue
|
|
listeners.push({
|
|
pid: parseInt(parts[1], 10) || 0,
|
|
command: parts[0],
|
|
user: parts[2],
|
|
type: parts[4], // IPv4 or IPv6
|
|
state: parts[9] || (proto === "udp" ? "UDP" : "UNKNOWN"),
|
|
address: parts[8] || `*:${port}`,
|
|
})
|
|
}
|
|
}
|
|
|
|
if (protocol === "tcp" || protocol === "both") {
|
|
runLsof("tcp")
|
|
}
|
|
if (protocol === "udp" || protocol === "both") {
|
|
runLsof("udp")
|
|
}
|
|
|
|
return JSON.stringify({
|
|
port,
|
|
protocol,
|
|
inUse: listeners.length > 0,
|
|
listeners,
|
|
}, null, 2)
|
|
} catch (err: any) {
|
|
return JSON.stringify({ error: err.message ?? String(err) }, null, 2)
|
|
}
|
|
},
|
|
})
|