Add bot graphics
Bots can now show a concept as a visual: create_graphic (with update_graphic, read_graphic and list_graphics, on every run, no computer needed) stores one HTML document in bot_graphics, per user like the conversation, and the chat renders its [graphic:ID] ref as an inline card sized to fit, with a large view and a page of its own (no rail). Graphic HTML is treated as hostile: it is only served at /graphics/<id> with a CSP sandbox allowing scripts under an origin of its own and no network, loading only the vendored Chart.js and Mermaid from /graphics-lib/. The document carries the app's theme vars and scrollbars, reports its height to the thread, and a frame that navigates away is closed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import graphicDocument from "./graphic-document";
|
||||
|
||||
const vars = {
|
||||
light: { "--c-paper": "#fff" },
|
||||
dark: { "--c-paper": "#000" },
|
||||
fonts: { "--font-sans": "sans-serif" },
|
||||
};
|
||||
|
||||
describe("graphicDocument", () => {
|
||||
test("wraps a fragment in a themed document", () => {
|
||||
const doc = graphicDocument({ html: "<svg></svg>", title: "A <b>", vars });
|
||||
|
||||
expect(doc.startsWith("<!DOCTYPE html><html><head>")).toBe(true);
|
||||
expect(doc).toContain("<title>A <b></title>");
|
||||
expect(doc).toContain("--c-paper:#fff;");
|
||||
expect(doc).toContain(":root.dark{color-scheme:dark;--c-paper:#000;}");
|
||||
expect(doc).toContain("<body><svg></svg><script>");
|
||||
expect(doc).toContain("cobble:graphic-size");
|
||||
});
|
||||
|
||||
test("styles scrollbars in the theme's colours", () => {
|
||||
const doc = graphicDocument({ html: "<p>x</p>", title: "T", vars });
|
||||
|
||||
expect(doc).toContain("::-webkit-scrollbar-thumb{background-color:var(--c-border-strong);");
|
||||
expect(doc).toContain("scrollbar-color:var(--c-border-strong) transparent;");
|
||||
});
|
||||
|
||||
test("puts the theme ahead of a whole document's own styles", () => {
|
||||
const doc = graphicDocument({
|
||||
html: `<!doctype html><html lang="en"><head><style>body{color:red}</style></head><body><p>Hi</p></body></html>`,
|
||||
title: "T",
|
||||
dark: true,
|
||||
vars,
|
||||
});
|
||||
|
||||
expect(doc.indexOf("--c-paper")).toBeLessThan(doc.indexOf("body{color:red}"));
|
||||
expect(doc).toContain(`classList.toggle("dark", true)`);
|
||||
expect(doc.indexOf("cobble:graphic-size")).toBeLessThan(doc.lastIndexOf("</body>"));
|
||||
expect(doc.match(/<!doctype/gi)?.length).toBe(1);
|
||||
});
|
||||
|
||||
test("gives a document without a head one", () => {
|
||||
const doc = graphicDocument({ html: `<html><body>x</body></html>`, title: "T", vars });
|
||||
|
||||
expect(doc).toContain(`<html><head><meta charset="utf-8">`);
|
||||
});
|
||||
|
||||
test("drops a refresh that would navigate the frame away", () => {
|
||||
const doc = graphicDocument({
|
||||
html: `<head><meta http-equiv="refresh" content="0;url=https://evil.test/?d=1"></head>`,
|
||||
title: "T",
|
||||
vars,
|
||||
});
|
||||
|
||||
expect(doc).not.toContain("evil.test");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user