diff --git a/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts b/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts index 60a200126c..221fafc866 100644 --- a/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts +++ b/packages/agent/src/adapters/claude/permissions/permission-handlers.test.ts @@ -200,7 +200,7 @@ describe("canUseTool MCP approval enforcement", () => { expect(result.behavior).toBe("allow"); }); - it("bypasses the PostHog exec gate in auto mode", async () => { + it("prompts through the PostHog exec gate in auto mode", async () => { setMcpToolApprovalStates({ mcp__posthog__exec: "approved" }); const hasApproval = vi.fn().mockReturnValue(false); const addApproval = vi.fn().mockResolvedValue(undefined); @@ -215,12 +215,23 @@ describe("canUseTool MCP approval enforcement", () => { addPostHogExecApproval: addApproval, }, }, + client: createClient({ + outcome: { outcome: "selected", optionId: "allow" }, + }), }); const result = await canUseTool(context); + // Auto mode only auto-approves file edits and shell commands; destructive + // PostHog sub-tools must still reach the client as a permission prompt. expect(result.behavior).toBe("allow"); - expect(context.client.requestPermission).not.toHaveBeenCalled(); - expect(hasApproval).not.toHaveBeenCalled(); + expect(hasApproval).toHaveBeenCalledWith("experiment-update"); + expect(context.client.requestPermission).toHaveBeenCalledWith( + expect.objectContaining({ + toolCall: expect.objectContaining({ + title: "The agent wants to run `experiment-update` on PostHog", + }), + }), + ); expect(addApproval).not.toHaveBeenCalled(); }); diff --git a/packages/agent/src/adapters/claude/permissions/permission-handlers.ts b/packages/agent/src/adapters/claude/permissions/permission-handlers.ts index 979f62140e..cfc8ccd3e1 100644 --- a/packages/agent/src/adapters/claude/permissions/permission-handlers.ts +++ b/packages/agent/src/adapters/claude/permissions/permission-handlers.ts @@ -778,10 +778,10 @@ export async function canUseTool( if (isPostHogExecTool(toolName)) { const subTool = extractPostHogSubTool(toolInput); if (subTool && isPostHogDestructiveSubTool(subTool)) { - if ( - session.permissionMode === "auto" || - session.permissionMode === "bypassPermissions" - ) { + // "auto" deliberately does NOT skip this gate: the mode only promises + // hands-off file edits and shell commands, and destructive PostHog + // sub-tools must still surface a permission prompt to the client. + if (session.permissionMode === "bypassPermissions") { return { behavior: "allow", updatedInput: toolInput as Record,