#!/usr/bin/env bun import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"; import { mkdtemp, readFile, rm, writeFile } from "fs/promises"; import { tmpdir } from "os"; import { join } from "path"; describe("runClaudeWithSdk", () => { const originalRunnerTemp = process.env.RUNNER_TEMP; let tempDir: string | undefined; afterEach(async () => { if (tempDir) { await rm(tempDir, { recursive: true, force: true }); tempDir = undefined; } process.env.RUNNER_TEMP = originalRunnerTemp; }); test("writes the execution file when the SDK throws after yielding messages", async () => { const consoleErrorSpy = spyOn(console, "error").mockImplementation( () => {}, ); const consoleLogSpy = spyOn(console, "log").mockImplementation(() => {}); tempDir = await mkdtemp(join(tmpdir(), "claude-sdk-")); process.env.RUNNER_TEMP = tempDir; const promptPath = join(tempDir, "prompt.txt"); await writeFile(promptPath, "test prompt"); const initMessage = { type: "system", subtype: "init", session_id: "session-123", model: "claude-sonnet-4-6", }; mock.module("@anthropic-ai/claude-agent-sdk", () => ({ query: async function* () { yield initMessage; throw new Error("Claude Code returned error_max_turns"); }, })); try { const { runClaudeWithSdk } = await import("../src/run-claude-sdk"); await expect( runClaudeWithSdk(promptPath, { sdkOptions: {}, showFullOutput: false, hasJsonSchema: false, }), ).rejects.toThrow("SDK execution error"); const executionFile = join(tempDir, "claude-execution-output.json"); await expect(readFile(executionFile, "utf-8")).resolves.toBe( JSON.stringify([initMessage], null, 2), ); } finally { consoleErrorSpy.mockRestore(); consoleLogSpy.mockRestore(); } }); });