import { describe, expect, it } from "bun:test"; import type { AgentToolContext } from "@oh-my-pi/pi-agent-core"; import type { BashInterceptorRule } from "../../src/config/settings-schema"; import type { ToolSession } from "../../src/tools"; import { BashTool } from "../../src/tools/bash"; function createBashTool(rules: BashInterceptorRule[]): BashTool { const session = { settings: { get(key: string) { if (key === "bashInterceptor.enabled") return true; if (key === "async.enabled") return false; if (key === "bash.autoBackground.enabled") return false; if (key === "bash.autoBackground.thresholdMs") return 60_000; return undefined; }, getBashInterceptorRules() { return rules; }, }, } as unknown as ToolSession; return new BashTool(session); } describe("BashTool interception", () => { it("checks the original command before leading cd normalization", async () => { const tool = createBashTool([ { pattern: "^\\s*cd\\s+", tool: "bash", message: "Do not hide directory changes in the command string.", }, ]); await expect( tool.execute("tool-call", { command: "cd packages/coding-agent && echo ok" }, undefined, undefined, { toolNames: ["bash"], } as AgentToolContext), ).rejects.toThrow("Do not hide directory changes"); }); it("checks the cwd-normalized command after leading cd normalization", async () => { const tool = createBashTool([ { pattern: "^\\s*cat\\s+", tool: "read", message: "Use read instead.", }, ]); await expect( tool.execute("tool-call", { command: "cd packages/coding-agent && cat package.json" }, undefined, undefined, { toolNames: ["read"], } as AgentToolContext), ).rejects.toThrow("Use read instead"); }); });