export async function checkToolExists(toolName: string): Promise { try { const command = new Deno.Command("which", { args: [toolName], stdout: "piped", stderr: "piped", }); const { code } = await command.output(); return code === 0; } catch { return false; } } export async function requireTool( toolName: string, installationInstructions: string, ): Promise { const exists = await checkToolExists(toolName); if (!exists) { console.warn(`\n⚠️ [Pre-flight Check] Tool '${toolName}' is missing.`); console.warn(` Please install it: ${installationInstructions}`); console.warn(` Skipping execution that depends on this tool.\n`); return false; } return true; } export async function execTool( toolName: string, args: string[], options?: { stdin?: string }, ): Promise<{ code: number; stdout: string; stderr: string }> { const commandOpts: Deno.CommandOptions = { args, stdout: "piped", stderr: "piped", }; if (options?.stdin) { commandOpts.stdin = "piped"; } const command = new Deno.Command(toolName, commandOpts); if (options?.stdin) { const process = command.spawn(); const writer = process.stdin.getWriter(); await writer.write(new TextEncoder().encode(options.stdin)); await writer.close(); const { code, stdout, stderr } = await process.output(); return { code, stdout: new TextDecoder().decode(stdout), stderr: new TextDecoder().decode(stderr), }; } const { code, stdout, stderr } = await command.output(); return { code, stdout: new TextDecoder().decode(stdout), stderr: new TextDecoder().decode(stderr), }; }