import { Type } from "typebox"; import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; import { guardedExec, type ParsedArgv } from "../verification/guarded-exec.js"; export function registerGuardedBash(pi: ExtensionAPI, validate?: (argv: ParsedArgv) => void | Promise): void { pi.registerTool({ name: "guarded_bash", label: "Guarded Bash", description: "Run one allowlisted verification or repository command. Shell operators and destructive commands are blocked; other commands require human approval.", parameters: Type.Object({ command: Type.String({ minLength: 1 }), timeoutMs: Type.Optional(Type.Integer({ minimum: 100, maximum: 120000 })) }), async execute(_id, params, _signal, _update, ctx) { try { const result = await guardedExec(params.command, ctx.cwd, params.timeoutMs ?? 30_000, validate); return { content: [{ type: "text", text: `${result.exitCode ?? "timeout"}\n${result.stdout}\n${result.stderr}`.trim() }], details: result }; } catch (error) { return { content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }], details: {}, isError: true }; } }, }); }