import { describe, it, expect, beforeEach } from "vitest"; import { mkdtemp, rm, writeFile, mkdir } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { ToolRegistry } from "../../src/agent/tools.js"; import { cphCheckTool, cphBuildTool } from "../../src/agent/cph.js"; const EXAMPLES_DIR = join(process.cwd(), "..", "examples", "TH-141"); describe("cph subprocess tools (integration, real cph binary)", () => { let ws: string; let tools: ToolRegistry; beforeEach(async () => { // Use the real TH-141 example as the workspace. ws = EXAMPLES_DIR; tools = new ToolRegistry(); tools.register(cphCheckTool()); tools.register(cphBuildTool()); }); it("cph_check runs on the TH-141 example and returns diagnostics", async () => { const ctx = { runId: "r", projectId: "p", boundChatId: "c", workspaceDir: ws }; const out = await tools.execute("cph_check", {}, ctx); const result = JSON.parse(out) as { exitCode: number; stdout: string; stderr: string }; // cph check exits 0 on a legal lesson (no error diagnostics, ADR-0010). // If the example has warnings, exit is still 0. expect(result.exitCode).toBe(0); }, 30000); it("cph_build renders the student target PDF", async () => { const ctx = { runId: "r", projectId: "p", boundChatId: "c", workspaceDir: ws }; const out = await tools.execute("cph_build", { target: "student", output: "build/test-student.pdf" }, ctx); const result = JSON.parse(out) as { exitCode: number; stdout: string; stderr: string; output: string }; expect(result.exitCode).toBe(0); }, 30000); it("cph_check on a temp dir with no engineering file returns non-zero", async () => { const empty = await mkdtemp(join(tmpdir(), "hub-cph-empty-")); try { const ctx = { runId: "r", projectId: "p", boundChatId: "c", workspaceDir: empty }; const out = await tools.execute("cph_check", {}, ctx); const result = JSON.parse(out) as { exitCode: number }; expect(result.exitCode).not.toBe(0); } finally { await rm(empty, { recursive: true, force: true }); } }, 15000); });