#!/usr/bin/env tsx // Usage: ./{function_name}.ts import { readFileSync, writeFileSync, existsSync, statSync } from "fs"; import { join, basename } from "path"; import { pathToFileURL } from "url"; async function main(): Promise { const rawData = parseArgv(); const toolData = parseRawData(rawData); const rootDir = "{root_dir}"; setupEnv(rootDir); const toolPath = "{tool_path}.ts"; await run(toolPath, "run", toolData); } function parseRawData(data: string): Record { if (!data) { throw new Error("No JSON data"); } try { return JSON.parse(data); } catch { throw new Error("Invalid JSON data"); } } function parseArgv(): string { const toolDataFile = process.env["LLM_TOOL_DATA_FILE"]; if (toolDataFile && existsSync(toolDataFile)) { return readFileSync(toolDataFile, "utf-8"); } const toolData = process.argv[2]; if (!toolData) { process.stderr.write("Usage: ./{function_name}.ts \n"); process.exit(1); } return toolData; } function setupEnv(rootDir: string): void { loadEnv(join(rootDir, ".env")); process.env["LLM_ROOT_DIR"] = rootDir; process.env["LLM_TOOL_NAME"] = "{function_name}"; process.env["LLM_TOOL_CACHE_DIR"] = join(rootDir, "cache", "{function_name}"); } function loadEnv(filePath: string): void { let lines: string[]; try { lines = readFileSync(filePath, "utf-8").split("\n"); } catch { return; } for (const raw of lines) { const line = raw.trim(); if (line.startsWith("#") || !line) { continue; } const eqIdx = line.indexOf("="); if (eqIdx === -1) { continue; } const key = line.slice(0, eqIdx).trim(); if (key in process.env) { continue; } let value = line.slice(eqIdx + 1).trim(); if ( (value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")) ) { value = value.slice(1, -1); } process.env[key] = value; } } function extractParamNames(fn: Function): string[] { const src = fn.toString(); const match = src.match(/^(?:async\s+)?function\s*\w*\s*\(([^)]*)\)/); if (!match) { return []; } return match[1] .split(",") .map((p) => p.trim().replace(/[:=?].*/s, "").trim()) .filter(Boolean); } function spreadArgs( fn: Function, data: Record, ): unknown[] { const names = extractParamNames(fn); if (names.length === 0) { return []; } return names.map((name) => data[name]); } async function run( toolPath: string, toolFunc: string, toolData: Record, ): Promise { const mod = await import(pathToFileURL(toolPath).href); if (typeof mod[toolFunc] !== "function") { throw new Error(`No module function '${toolFunc}' at '${toolPath}'`); } const fn = mod[toolFunc] as Function; const args = spreadArgs(fn, toolData); const value = await fn(...args); returnToLlm(value); dumpResult("{function_name}"); } function returnToLlm(value: unknown): void { if (value === null || value === undefined) { return; } const output = process.env["LLM_OUTPUT"]; const write = (s: string) => { if (output) { writeFileSync(output, s, "utf-8"); } else { process.stdout.write(s); } }; if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") { write(String(value)); } else if (typeof value === "object") { write(JSON.stringify(value, null, 2)); } } function dumpResult(name: string): void { const dumpResults = process.env["LLM_DUMP_RESULTS"]; const llmOutput = process.env["LLM_OUTPUT"]; if (!dumpResults || !llmOutput || !process.stdout.isTTY) { return; } try { const pattern = new RegExp(`\\b(${dumpResults})\\b`); if (!pattern.test(name)) { return; } } catch { return; } let data: string; try { data = readFileSync(llmOutput, "utf-8"); } catch { return; } process.stdout.write( `\x1b[2m----------------------\n${data}\n----------------------\x1b[0m\n`, ); } main().catch((err) => { process.stderr.write(`${err}\n`); process.exit(1); });