mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-10 15:09:00 +02:00
Ten catalog ids carry `mockupNever` (kicker-above-heading, icon-tile-stack, gradient-text, ai-color-palette, cream-palette, nested-cards, dark-glow, pulsing-dot, identical-cards, hero-metrics) and lib/design-catalog.ts exports their deduped plain-English names as MOCKUP_NEVER_NAMES. briefToPrompt() in the design binary appends "Never: <names>." before its fixed tail, so `$D generate | variants | evolve` stop reaching for purple gradients, icon tiles, and cream defaults before the comparison board opens. The binary still bundles (`bun build --compile design/src/cli.ts`); ./setup rebuilds it. design-html's Never-include list now covers every mockupNever id (kicker / icon tile, hero metric rows, gradient text, cream palette, nested and identical cards, glow and pulsing dots), each line tagged with its catalog ids; test/design-catalog.test.ts pins the exact ten flags, the deduped names, and that the template list is a superset. New design/test/brief.test.ts pins the prompt shape. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
45 lines
2.0 KiB
TypeScript
45 lines
2.0 KiB
TypeScript
/**
|
|
* briefToPrompt carries the catalog's generation-time slop guard.
|
|
*
|
|
* The "Never:" line is built from MOCKUP_NEVER_NAMES (lib/design-catalog.ts),
|
|
* so the image model is told up front what not to reach for. The catalog test
|
|
* owns the "exactly ten ids" invariant; this one pins the prompt shape.
|
|
*/
|
|
import { describe, expect, test } from "bun:test";
|
|
import { briefToPrompt, type DesignBrief } from "../src/brief";
|
|
import { MOCKUP_NEVER_NAMES } from "../../lib/design-catalog";
|
|
|
|
const brief: DesignBrief = {
|
|
goal: "Dashboard for a coding assessment tool",
|
|
audience: "Technical users",
|
|
style: "Dark theme, minimal",
|
|
elements: ["builder name", "score badge"],
|
|
screenType: "desktop-dashboard",
|
|
};
|
|
|
|
describe("briefToPrompt", () => {
|
|
test("carries a Never: line listing every MOCKUP_NEVER_NAMES entry, before the fixed tail", () => {
|
|
const prompt = briefToPrompt(brief);
|
|
const never = `Never: ${MOCKUP_NEVER_NAMES.join(", ")}.`;
|
|
expect(prompt).toContain(never);
|
|
expect(MOCKUP_NEVER_NAMES.length).toBeGreaterThanOrEqual(8);
|
|
for (const name of MOCKUP_NEVER_NAMES) expect(prompt).toContain(name);
|
|
expect(prompt.indexOf(never)).toBeLessThan(prompt.indexOf("The mockup should look like a real production UI"));
|
|
expect(prompt.indexOf(never)).toBeGreaterThan(prompt.indexOf("Required elements:"));
|
|
});
|
|
|
|
test("names are plain English: no hyphenated rule ids leak into the prompt", () => {
|
|
const prompt = briefToPrompt(brief);
|
|
expect(prompt).not.toMatch(/\b[a-z]+(-[a-z]+)+\b(?=[,.])/);
|
|
for (const name of MOCKUP_NEVER_NAMES) expect(name).not.toMatch(/^[a-z0-9]+(-[a-z0-9]+)+$/);
|
|
});
|
|
|
|
test("optional fields still render around the guard", () => {
|
|
const prompt = briefToPrompt({ ...brief, constraints: "Max width 1024px", reference: "DESIGN.md excerpt" });
|
|
expect(prompt).toContain("Constraints: Max width 1024px.");
|
|
expect(prompt).toContain("Design reference: DESIGN.md excerpt");
|
|
expect(prompt).toContain("Never: ");
|
|
expect(prompt.endsWith("1536x1024 pixels.")).toBe(true);
|
|
});
|
|
});
|