d8e38bcc62
- AcpAgent integration tests: initialize→run→notify cycle, notification structure, message-ID continuity - ACP built-in slash command unit tests across all command handlers via fake runtime - ACP event mapper unit tests: text chunks, thinking, tool calls/results, errors → SessionNotification - ACP initialize conformance: terminal auth capability negotiation, agentInfo/agentCapabilities contract - stdout hygiene smoke test: first bytes on omp acp stdout must be a valid JSON-RPC frame - AgentSession permission gate: allow-once, reject-once, allow-always, abort-during-pending, non-gated tools - BashTool ACP terminal routing: bridge dispatch vs local PTY fallback - EditTool diff content propagation: patch, replace, and multi-file aggregation paths - ReadTool and WriteTool ACP filesystem permission tests - Shared ACP schema test helper
63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, spyOn } from "bun:test";
|
|
import * as fs from "node:fs/promises";
|
|
import * as os from "node:os";
|
|
import * as path from "node:path";
|
|
import { Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
|
|
import type { ClientBridge } from "@oh-my-pi/pi-coding-agent/session/client-bridge";
|
|
import type { ToolSession } from "@oh-my-pi/pi-coding-agent/tools";
|
|
import { WriteTool } from "@oh-my-pi/pi-coding-agent/tools/write";
|
|
|
|
const FILE_CONTENT = "bridge write content\n";
|
|
|
|
function createSession(cwd: string, bridge?: ClientBridge): ToolSession {
|
|
return {
|
|
cwd,
|
|
hasUI: false,
|
|
getSessionFile: () => path.join(cwd, "session.jsonl"),
|
|
getSessionSpawns: () => "*",
|
|
getArtifactsDir: () => path.join(cwd, "artifacts"),
|
|
allocateOutputArtifact: async () => ({ id: "artifact-1", path: path.join(cwd, "artifact-1.log") }),
|
|
settings: Settings.isolated(),
|
|
getClientBridge: bridge ? () => bridge : undefined,
|
|
};
|
|
}
|
|
|
|
describe("write tool ACP fs routing", () => {
|
|
let tmpDir: string;
|
|
|
|
beforeEach(async () => {
|
|
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "write-acp-fs-test-"));
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("routes plain text writes through the bridge and does not call Bun.write", async () => {
|
|
const filePath = path.join(tmpDir, "output.txt");
|
|
|
|
const bridge: ClientBridge = {
|
|
capabilities: { writeTextFile: true },
|
|
writeTextFile: async () => undefined,
|
|
};
|
|
|
|
const bridgeSpy = spyOn(bridge, "writeTextFile");
|
|
const bunWriteSpy = spyOn(Bun, "write");
|
|
|
|
try {
|
|
const session = createSession(tmpDir, bridge);
|
|
const tool = new WriteTool(session);
|
|
|
|
await tool.execute("call-1", { path: filePath, content: FILE_CONTENT });
|
|
|
|
// Bridge was called with the exact path and content
|
|
expect(bridgeSpy).toHaveBeenCalledTimes(1);
|
|
expect(bridgeSpy).toHaveBeenCalledWith({ path: filePath, content: FILE_CONTENT });
|
|
// Disk write must not have been called — bridge is the destination
|
|
expect(bunWriteSpy).not.toHaveBeenCalled();
|
|
} finally {
|
|
bunWriteSpy.mockRestore();
|
|
}
|
|
});
|
|
});
|