import { test, expect, afterEach } from "bun:test"; import { mkdtempSync, rmSync, writeFileSync, readFileSync, mkdirSync, existsSync } from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { createFrameworkMcpServer } from "../../mcp/src/index.ts"; import { DesignAgentService } from "../src/agent-server.ts"; import { agentGenerationContext } from "../src/agent-context.ts"; import { checkDesignConformance } from "../src/conformance.ts"; import { agentPageSource, checkAgentPage, type AgentPage } from "../src/agent-pages.ts"; import { CORE_DESIGN_SYSTEMS } from "../../design-system/src/index.ts"; import { compileWrnFile } from "../../compiler/src/index.ts"; const roots: string[] = []; function root() { const path = mkdtempSync(join(tmpdir(), "wrn-phase6-")); roots.push(path); writeFileSync(join(path, "package.json"), "{}"); return path; } afterEach(() => { for (const path of roots.splice(0)) rmSync(path, { recursive: true, force: true }); }); const page = (id: string): AgentPage => ({ id, title: id === "account" ? "Account settings" : "Contact support", components: [ { component: "PageHeader", props: { title: "Your workspace" } }, { component: "Input", props: { id: id + "-name", label: "Name" } }, { component: "Button", props: { label: "Continue", variant: "default" } }, ], }); test("MCP defaults stay unchanged; explicit design opt-in exposes read tools and separate write opt-in", async () => { const path = root(); expect(createFrameworkMcpServer(path).tools()).toHaveLength(8); const readonly = createFrameworkMcpServer(path, { design: true }); expect(readonly.tools().some((t) => t.name === "wrnexus_design_context")).toBe(true); expect(readonly.tools().some((t) => t.name === "wrnexus_design_apply")).toBe(false); expect( ((await readonly.call("wrnexus_design_context")) as any).components.Button.parts, ).toBeDefined(); expect(existsSync(join(path, ".wrnexus"))).toBe(false); const response = await readonly.handle({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name: "wrnexus_design_apply", arguments: { baseRevision: "none" } }, }); expect((response as any).result.isError).toBe(true); }); test("recover invalid edits, stale conflicts, locks, undo and checkpoints across service instances", async () => { const path = root(); let service = new DesignAgentService(path, true); let draft: any = await service.call("create", { baseRevision: "none" }); const first = draft.revision; draft = await service.call("locks", { baseRevision: first, locks: ["/tokens/color.primary"] }); await expect(service.call("create", { baseRevision: first })).rejects.toThrow("CONFLICT"); draft = await service.call("propose", { baseRevision: draft.revision, source: "{unfinished" }); expect(draft.diagnostics.length).toBeGreaterThan(0); service = new DesignAgentService(path, true); let state: any = await service.call("inspect"); expect(state.source).toBe("{unfinished"); expect(state.valid.id).toBe("square"); await expect( service.call("apply", { baseRevision: state.revision, baseApplicationRevision: "none" }), ).rejects.toThrow("INVALID"); draft = await service.call("revert", { baseRevision: state.revision }); state = await service.call("inspect"); expect(state.diagnostics).toEqual([]); const locked = structuredClone(state.valid); locked.tokens["color.primary"].value = "#abcdef"; draft = await service.call("propose", { baseRevision: draft.revision, source: JSON.stringify(locked), }); expect(draft.diagnostics.length).toBeGreaterThan(0); await service.call("revert", { baseRevision: draft.revision, target: "checkpoint" }); state = await service.call("inspect"); expect(state.diagnostics).toEqual([]); expect(state.locks).toEqual(["/tokens/color.primary"]); }); test("agents create two compilable consistent pages across all three designs and both modes", async () => { for (const system of Object.values(CORE_DESIGN_SYSTEMS)) { const service = new DesignAgentService(root(), true); let draft: any = await service.call("create", { baseRevision: "none", source: JSON.stringify(system), }); for (const id of ["account", "support"]) { draft = await service.call("page", { baseRevision: draft.revision, page: page(id) }); expect(draft.result.ok).toBe(true); const source = agentPageSource(page(id)); expect(checkDesignConformance(source).ok).toBe(true); expect(compileWrnFile(source)).toBeTruthy(); } for (const mode of ["light", "dark"]) for (const id of ["account", "support"]) { const preview: any = await service.call("preview", { pageId: id, mode }); expect(preview.html).toContain("Content-Security-Policy"); expect(preview.html).toContain('data-wrn-component="Button"'); expect(preview.html).toContain('data-theme="' + mode + '"'); expect(preview.html).toContain("--wrn-radius"); } const exported: any = await service.call("export"); expect(Object.keys(exported.pages)).toEqual(["account.wrn", "support.wrn"]); expect(((await service.call("validate")) as any).ok).toBe(true); } }); test("conformance rejects invented axes and props; only exact warnings can be waived", () => { const source = 'page Test { view {
} style { main { color: #fff; padding: 17px; } } }'; const report = checkDesignConformance(source); expect(report.ok).toBe(false); expect(report.diagnostics.some((d) => d.code === "WRN-CONFORMANCE-AXIS")).toBe(true); expect(report.diagnostics.some((d) => d.code === "WRN-CONFORMANCE-PROP")).toBe(true); const warning = "page Test { view {
Test
} style { main { color: #fff; } } }"; const d = checkDesignConformance(warning).diagnostics[0]!; expect( checkDesignConformance(warning, [ { code: d.code, path: d.path, reason: "Reviewed brand illustration" }, ]).ok, ).toBe(true); expect( checkDesignConformance(source, [ { code: "WRN-CONFORMANCE-AXIS", path: "$.view[0].variant", reason: "No" }, ]).ok, ).toBe(false); expect(checkDesignConformance("broken").ok).toBe(false); expect( checkAgentPage({ ...page("account"), components: [{ component: "Button", props: { variant: "invented" } }], }).ok, ).toBe(false); expect( checkAgentPage({ ...page("account"), components: [{ component: "Button", props: { label: "javascript:alert(1)" } }], }).ok, ).toBe(false); }); test("application revision checks, exports and reversal preserve existing app configuration", async () => { const path = root(); writeFileSync(join(path, "wrn.config.ts"), "existing config"); const service = new DesignAgentService(path, true); let draft: any = await service.call("create", { baseRevision: "none" }); await expect( service.call("apply", { baseRevision: draft.revision, baseApplicationRevision: "stale" }), ).rejects.toThrow("CONFLICT"); draft = await service.call("apply", { baseRevision: draft.revision, baseApplicationRevision: "none", }); expect(draft.result.revision).not.toBe("none"); expect(readFileSync(join(path, "wrn.config.ts"), "utf8")).toBe("existing config"); const reverted: any = await service.call("revert", { baseRevision: draft.revision, target: "application", baseApplicationRevision: draft.result.revision, }); expect(reverted.result.revision).toBe("none"); mkdirSync(join(path, ".wrnexus", "design-studio", "agent", "LOCK")); await expect(service.call("create", { baseRevision: reverted.revision })).rejects.toThrow("BUSY"); }); test("agent context carries resolved tokens and real contract boundaries, with bounded selection", () => { for (const system of Object.values(CORE_DESIGN_SYSTEMS)) { const context = agentGenerationContext(system, { components: ["Button", "Input"] }); expect(Object.keys(context.components)).toEqual(["Button", "Input"]); expect(context.tokens["color.primary"]).toBeDefined(); expect((context.components.Button.axes as any).variant.values).toContain("default"); } expect(() => agentGenerationContext(CORE_DESIGN_SYSTEMS.square, { components: ["Invented"] }), ).toThrow("CONTEXT"); }); test("stdio design protocol advertises opt-in tools and returns structured context without model credentials", async () => { const child = Bun.spawn(["bun", "packages/mcp/src/stdio.ts", "--root=" + root(), "--design"], { stdin: "pipe", stdout: "pipe", stderr: "pipe", }); child.stdin.write( JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" }) + "\n" + JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "wrnexus_design_context", arguments: { components: ["Button"] } }, }) + "\n", ); child.stdin.end(); const lines = (await new Response(child.stdout).text()) .trim() .split("\n") .map((line) => JSON.parse(line)); expect(await child.exited).toBe(0); expect(lines[0].result.tools.some((t: any) => t.name === "wrnexus_design_context")).toBe(true); expect(lines[1].result.structuredContent.value.components.Button).toBeDefined(); }); test("exported pages preserve literal string, boolean and structured props in compiled mount markup", async () => { const source = agentPageSource({ id: "literal-props", title: "Literal props", components: [ { component: "Button", props: { label: "Continue", disabled: false } }, { component: "Select", props: { options: [{ label: "One", value: "one" }] } }, ], }); const code = new Bun.Transpiler({ loader: "ts" }).transformSync( compileWrnFile(source).replace( /from (["'])@wrnexus\/core\1/g, `from ${JSON.stringify(new URL("../../core/src/index.ts", import.meta.url).href)}`, ), ); const mod = await import("data:text/javascript;base64," + Buffer.from(code).toString("base64")); const html = await mod.default({}); expect(html).toContain('label="Continue"'); expect(html).toContain('disabled="false"'); expect(html).toContain( 'options="[{"label":"One","value":"one"}]"', ); }); import { createDesignPackage } from "@wrnexus/design-system/package"; test("MCP package upgrades preserve history and reject future agent storage without overwriting it", async () => { const path = root(); const server = createFrameworkMcpServer(path, { design: true, designWrite: true }); let draft: any = await server.call("wrnexus_design_create", { baseRevision: "none" }); const next = structuredClone(CORE_DESIGN_SYSTEMS.square); next.version = "1.2.0"; const source = JSON.stringify(await createDesignPackage(next)); expect(((await server.call("wrnexus_design_upgrade_plan", { source })) as any).canApply).toBe( true, ); draft = await server.call("wrnexus_design_upgrade", { baseRevision: draft.revision, source }); expect(((await server.call("wrnexus_design_inspect")) as any).valid.version).toBe("1.2.0"); await expect( server.call("wrnexus_design_upgrade", { baseRevision: "none", source }), ).rejects.toThrow("CONFLICT"); await server.call("wrnexus_design_revert", { baseRevision: draft.revision }); expect(((await server.call("wrnexus_design_inspect")) as any).valid.version).toBe("1.0.0"); const file = join(path, ".wrnexus", "design-studio", "agent", "STATE.json"); const state = JSON.parse(readFileSync(file, "utf8")); const future = JSON.stringify({ ...state, storageVersion: 2 }); writeFileSync(file, future); await expect( server.call("wrnexus_design_create", { baseRevision: state.revision }), ).rejects.toThrow("RECOVERY"); expect(readFileSync(file, "utf8")).toBe(future); });