@ggui-ai/ui-gen 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/generation-dispatch.d.ts +24 -4
- package/dist/adapters/generation-dispatch.js +5188 -3920
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +33 -26
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +22 -13
- package/dist/advanced/index.js +4889 -3561
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +8 -12
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.d.ts +19 -1
- package/dist/boilerplate.js +671 -254
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +17 -3
- package/dist/check/index.js +34 -25
- package/dist/check/index.js.map +1 -1
- package/dist/compose.js +1 -1
- package/dist/compose.js.map +1 -1
- package/dist/create-ui-generator-C8Ki9Wz1.d.ts +189 -0
- package/dist/design-mode-DLufhrNp.d.ts +61 -0
- package/dist/{dispatch-BuZfTh9r.d.ts → dispatch-D2htzi9h.d.ts} +4 -1
- package/dist/evaluation/axis-checks/index.d.ts +4 -3
- package/dist/evaluation/axis-checks/index.js +300 -14
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +2 -1
- package/dist/evaluation/axis-checks/registry.js +253 -1
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +297 -5
- package/dist/evaluation/index.js +4515 -120
- package/dist/evaluation/index.js.map +1 -1
- package/dist/fragments/index.js +1 -1
- package/dist/fragments/index.js.map +1 -1
- package/dist/{generate-BTfvELgl.d.ts → generate-9IeNT4ZY.d.ts} +10 -1
- package/dist/harness/check/runtime-render/index.d.ts +3 -1
- package/dist/harness/check/runtime-render/index.js +8 -12
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/index.d.ts +3 -1
- package/dist/harness/index.js +913 -441
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.d.ts +3 -3
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.d.ts +2 -1
- package/dist/harness/prompts.js +6 -3
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +17 -5
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +28 -3
- package/dist/harness/runtime.js +702 -274
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +39 -1
- package/dist/harness/types-public.js +913 -441
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +2 -1
- package/dist/index.d.ts +32 -6
- package/dist/index.js +4899 -3560
- package/dist/index.js.map +1 -1
- package/dist/patch.d.ts +3 -1
- package/dist/{prompts-BVhtH3M1.d.ts → prompts-YU9piOgs.d.ts} +21 -45
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/styling-profile-CxfvV48g.d.ts +35 -0
- package/dist/tools/get-primitives-ts.d.ts +1 -1
- package/dist/tools/get-primitives-ts.js +1 -1
- package/dist/tools/get-primitives-ts.js.map +1 -1
- package/dist/{types-public-CkNWEov9.d.ts → types-public-DVSssdc-.d.ts} +85 -5
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +4 -4
- package/dist/validation/index.js.map +1 -1
- package/dist/workflows.d.ts +3 -1
- package/package.json +12 -12
- package/src/adapters/generation-dispatch.ts +62 -4
- package/src/adapters/provider-router.ts +7 -6
- package/src/adapters/tools.ts +5 -5
- package/src/advanced/generator.ts +11 -10
- package/src/advanced/index.ts +5 -4
- package/src/boilerplate/free-design-prompt.ts +336 -0
- package/src/boilerplate/generate.ts +10 -1
- package/src/boilerplate/hard-sections.ts +257 -0
- package/src/boilerplate/render.ts +32 -8
- package/src/boilerplate/styling-profile.ts +166 -0
- package/src/boilerplate/system-prompt.ts +101 -237
- package/src/boilerplate/templates/base-free.tsx.tmpl +24 -0
- package/src/check/run-tier0.ts +82 -20
- package/src/coding-agent/tools.ts +8 -2
- package/src/contract-context.ts +43 -14
- package/src/create-harness.ts +15 -0
- package/src/create-ui-generator.ts +112 -27
- package/src/design-mode.ts +192 -0
- package/src/design-system-docs.ts +24 -17
- package/src/effort.ts +48 -0
- package/src/evaluation/axis-checks/checks/grid.ts +148 -0
- package/src/evaluation/axis-checks/checks/universal.ts +244 -0
- package/src/evaluation/axis-checks/dispatch.ts +82 -13
- package/src/evaluation/axis-checks/extras.ts +5 -0
- package/src/evaluation/axis-checks/helpers.ts +12 -0
- package/src/evaluation/axis-checks/registry.ts +2 -0
- package/src/evaluation/cost-tracker.ts +2 -3
- package/src/evaluation/design-identity.ts +96 -0
- package/src/evaluation/index.ts +63 -2
- package/src/evaluation/llm-evaluator.ts +89 -21
- package/src/evaluation/theme-css.ts +14 -0
- package/src/evaluation/types-public.ts +137 -8
- package/src/evaluation/visual-evaluator.ts +759 -54
- package/src/fragments/render.ts +1 -1
- package/src/harness/check/runtime-render/prepare-mockup.ts +18 -11
- package/src/harness/coding/dupe-break.ts +0 -0
- package/src/harness/coding/init-session.ts +2 -0
- package/src/harness/coding/run-coding-turn.ts +9 -14
- package/src/harness/coding/run-eval-round.ts +46 -5
- package/src/harness/llm-trace-sink.ts +3 -3
- package/src/harness/result-types.ts +15 -3
- package/src/harness/runtime.ts +28 -0
- package/src/harness/types-public.ts +38 -0
- package/src/index.ts +28 -0
- package/src/internal/extract-call-signatures.ts +2 -2
- package/src/pin-fixtures.ts +98 -0
- package/src/providers/bedrock.ts +4 -4
- package/src/run-check.ts +11 -10
- package/src/tools/get-primitives-ts.ts +1 -1
- package/src/tools.ts +2 -1
- package/src/validation/allowed-imports.ts +8 -2
- package/src/validation/primitives.ts +1 -1
- package/dist/create-ui-generator-D6TKuv9V.d.ts +0 -106
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { LUCIDE_ICON_NAMES } from '@ggui-ai/design';
|
|
1
2
|
import { listContractGadgets, HOOK_NAME_RE, STDLIB_GADGETS_PACKAGE } from '@ggui-ai/protocol';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
2
4
|
|
|
3
|
-
// src/evaluation/axis-checks/
|
|
5
|
+
// src/evaluation/axis-checks/checks/universal.ts
|
|
4
6
|
var ID_FIELD_CANDIDATES = ["id", "uuid", "symbol", "key", "slug", "code"];
|
|
5
7
|
function getItemsProperties(p) {
|
|
6
8
|
return p.items?.properties ?? p.schema?.items?.properties;
|
|
@@ -157,6 +159,9 @@ function mkIssue(subcategory, description, fix, result = "fail") {
|
|
|
157
159
|
function cap(s) {
|
|
158
160
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
159
161
|
}
|
|
162
|
+
function axisCheckTraceEnabled() {
|
|
163
|
+
return process.env["GGUI_AXIS_CHECK_TRACE"] === "1";
|
|
164
|
+
}
|
|
160
165
|
|
|
161
166
|
// src/evaluation/axis-checks/checks/universal.ts
|
|
162
167
|
var ALL_RENDER_VALUES = [
|
|
@@ -260,7 +265,172 @@ function runPropSeedNoResync(input) {
|
|
|
260
265
|
}
|
|
261
266
|
return issues;
|
|
262
267
|
}
|
|
268
|
+
var KNOWN_ICON_KEYS = new Set(
|
|
269
|
+
LUCIDE_ICON_NAMES.map((n) => n.replace(/[-_]/g, "").toLowerCase())
|
|
270
|
+
);
|
|
271
|
+
function isKnownIconName(name) {
|
|
272
|
+
return KNOWN_ICON_KEYS.has(name.replace(/[-_]/g, "").toLowerCase());
|
|
273
|
+
}
|
|
274
|
+
var ICON_NAME_LITERAL_RX = /<Icon\b[^>]*?\bname\s*=\s*(?:"([^"]*)"|'([^']*)'|\{\s*"([^"]*)"\s*\}|\{\s*'([^']*)'\s*\})/g;
|
|
275
|
+
function findUnknownIconNames(sourceCode) {
|
|
276
|
+
const unknown = /* @__PURE__ */ new Set();
|
|
277
|
+
for (const m of sourceCode.matchAll(ICON_NAME_LITERAL_RX)) {
|
|
278
|
+
const name = m[1] ?? m[2] ?? m[3] ?? m[4] ?? "";
|
|
279
|
+
if (name.length === 0) continue;
|
|
280
|
+
if (/[^\x20-\x7e]/.test(name)) continue;
|
|
281
|
+
if (!isKnownIconName(name)) unknown.add(name);
|
|
282
|
+
}
|
|
283
|
+
return [...unknown];
|
|
284
|
+
}
|
|
285
|
+
function runIconNameKnown(input) {
|
|
286
|
+
if (input.compiledCode === null) return [];
|
|
287
|
+
const unknown = findUnknownIconNames(input.sourceCode);
|
|
288
|
+
if (unknown.length === 0) return [];
|
|
289
|
+
const list = unknown.map((n) => `"${n}"`).join(", ");
|
|
290
|
+
return [
|
|
291
|
+
mkIssue(
|
|
292
|
+
"universal.icon_name_known",
|
|
293
|
+
`<Icon name=\u2026> uses ${unknown.length} name(s) outside the design system's Lucide subset: ${list} \u2014 an unknown name renders an empty box.`,
|
|
294
|
+
"Call get_available_icons and pick a listed name (kebab-case), or use an emoji directly."
|
|
295
|
+
)
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
var LADDER_STOP_AS_TEXT_RX = /(?<![\w-])color\s*(?:=\s*\{?\s*|:\s*)["'`]?\s*var\(--ggui-color-primary-(\d{2,3})\s*[,)]/g;
|
|
299
|
+
var TEXT_INK_STOP_MIN = 300;
|
|
300
|
+
var TEXT_INK_STOP_MAX = 600;
|
|
301
|
+
function findLadderStopsAsText(sourceCode) {
|
|
302
|
+
const found = /* @__PURE__ */ new Set();
|
|
303
|
+
for (const m of sourceCode.matchAll(LADDER_STOP_AS_TEXT_RX)) {
|
|
304
|
+
const digits = m[1] ?? "";
|
|
305
|
+
const stop = Number(digits);
|
|
306
|
+
if (stop >= TEXT_INK_STOP_MIN && stop <= TEXT_INK_STOP_MAX) found.add(`primary-${digits}`);
|
|
307
|
+
}
|
|
308
|
+
return [...found];
|
|
309
|
+
}
|
|
310
|
+
function runAccentTextInk(input) {
|
|
311
|
+
if (input.compiledCode === null) return [];
|
|
312
|
+
const stops = findLadderStopsAsText(input.sourceCode);
|
|
313
|
+
if (stops.length === 0) return [];
|
|
314
|
+
const list = stops.map((s) => `\`${s}\``).join(", ");
|
|
315
|
+
return [
|
|
316
|
+
mkIssue(
|
|
317
|
+
"universal.accent_text_ink",
|
|
318
|
+
`Text is painted with a brand-ladder fill stop as its color (${list}) \u2014 on a low-saturation brand these stops are mid-grey on the surface and the text fails readability.`,
|
|
319
|
+
'Accent text (eyebrows, taglines, links, labels, inline arrows) takes var(--ggui-color-link) or <Text tone="emphasized">; body text takes var(--ggui-color-onContainer); keep primary-* stops on fills and borders.'
|
|
320
|
+
)
|
|
321
|
+
];
|
|
322
|
+
}
|
|
323
|
+
var SCOPED_SURFACE_TAG_RX = /<(Card|Box)\b([^<>]*?)surface\s*=\s*["'](inverted|hero)["']([^<>]*?)>/g;
|
|
324
|
+
var STYLE_BACKGROUND_RX = /\bstyle\s*=\s*\{\{[^}]*\b(background|backgroundColor|backgroundImage)\s*:/;
|
|
325
|
+
function findScopedSurfaceBackgrounds(sourceCode) {
|
|
326
|
+
const hits = [];
|
|
327
|
+
for (const m of sourceCode.matchAll(SCOPED_SURFACE_TAG_RX)) {
|
|
328
|
+
const attrs = `${m[2] ?? ""} ${m[4] ?? ""}`;
|
|
329
|
+
if (STYLE_BACKGROUND_RX.test(attrs)) hits.push([m[1] ?? "", m[3] ?? ""]);
|
|
330
|
+
}
|
|
331
|
+
return hits;
|
|
332
|
+
}
|
|
333
|
+
function runScopedSurfaceOwnsGround(input) {
|
|
334
|
+
if (input.compiledCode === null) return [];
|
|
335
|
+
if (input.designMode === "free") return [];
|
|
336
|
+
const hits = findScopedSurfaceBackgrounds(input.sourceCode);
|
|
337
|
+
if (hits.length === 0) return [];
|
|
338
|
+
const [tag, surface] = hits[0];
|
|
339
|
+
return [
|
|
340
|
+
mkIssue(
|
|
341
|
+
"universal.scoped_surface_owns_ground",
|
|
342
|
+
`<${tag} surface="${surface}"> sets its own background in style \u2014 a scoped surface owns its ground; repainting it puts the scope's swapped inks over the wrong ground (ink on ink).`,
|
|
343
|
+
`Remove the background from that ${tag}'s style \u2014 surface="${surface}" paints the ground; pick another surface if a different ground is wanted.`
|
|
344
|
+
)
|
|
345
|
+
];
|
|
346
|
+
}
|
|
347
|
+
var CAPS_TEXT_RX = /<Text\b(?=[^>]*\bcaps\b)[^>]*>([\s\S]*?)<\/Text>/g;
|
|
348
|
+
function findInventedCapsLabels(sourceCode) {
|
|
349
|
+
const out = [];
|
|
350
|
+
for (const m of sourceCode.matchAll(CAPS_TEXT_RX)) {
|
|
351
|
+
const inner = (m[1] ?? "").trim();
|
|
352
|
+
if (inner.length === 0) continue;
|
|
353
|
+
if (inner.includes("{")) continue;
|
|
354
|
+
out.push(inner.replace(/\s+/g, " ").slice(0, 60));
|
|
355
|
+
}
|
|
356
|
+
return out;
|
|
357
|
+
}
|
|
358
|
+
function runCapsLabelInvented(input) {
|
|
359
|
+
if (input.compiledCode === null) return [];
|
|
360
|
+
const invented = findInventedCapsLabels(input.sourceCode);
|
|
361
|
+
if (invented.length === 0) return [];
|
|
362
|
+
const list = invented.map((t) => `"${t}"`).join(", ");
|
|
363
|
+
return [
|
|
364
|
+
mkIssue(
|
|
365
|
+
"universal.caps_label_invented",
|
|
366
|
+
`${invented.length} caps label(s) carry invented copy the props do not supply: ${list} \u2014 an eyebrow, kicker or overline the agent cannot change is chatter on every render.`,
|
|
367
|
+
"Remove the label, or bind its text to a prop (`<Text caps>{props.section}</Text>`); copy comes from the contract, never from the component."
|
|
368
|
+
)
|
|
369
|
+
];
|
|
370
|
+
}
|
|
371
|
+
var VIEWPORT_UNIT = String.raw`(?:calc\(\s*)?100(?:vh|dvh|svh|lvh)\b(?:[^)"'\x60;\n]*\))?`;
|
|
372
|
+
var VIEWPORT_STYLE_OBJECT_RX = new RegExp(
|
|
373
|
+
String.raw`\b(?:minHeight|height|minBlockSize|blockSize)\s*:\s*["'\x60]\s*${VIEWPORT_UNIT}["'\x60]?`,
|
|
374
|
+
"g"
|
|
375
|
+
);
|
|
376
|
+
var VIEWPORT_CSS_RX = new RegExp(
|
|
377
|
+
String.raw`(?<![\w-])(?:min-)?(?:height|block-size)\s*:\s*${VIEWPORT_UNIT}`,
|
|
378
|
+
"g"
|
|
379
|
+
);
|
|
380
|
+
var VIEWPORT_CLASS_RX = /(?<![\w-])(?:min-)?h-(?:screen|dvh|svh|lvh)\b/g;
|
|
381
|
+
function findViewportSizing(sourceCode) {
|
|
382
|
+
const hits = [];
|
|
383
|
+
for (const rx of [VIEWPORT_STYLE_OBJECT_RX, VIEWPORT_CSS_RX, VIEWPORT_CLASS_RX]) {
|
|
384
|
+
for (const m of sourceCode.matchAll(rx)) {
|
|
385
|
+
hits.push({ at: m.index ?? 0, text: m[0].replace(/\s+/g, " ").trim().slice(0, 60) });
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
return hits.sort((a, b) => a.at - b.at).map((h) => h.text);
|
|
389
|
+
}
|
|
390
|
+
function runViewportSized(input) {
|
|
391
|
+
if (input.compiledCode === null) return [];
|
|
392
|
+
const sized = findViewportSizing(input.sourceCode);
|
|
393
|
+
if (sized.length === 0) return [];
|
|
394
|
+
const list = sized.map((t) => "`" + t + "`").join(", ");
|
|
395
|
+
return [
|
|
396
|
+
mkIssue(
|
|
397
|
+
"universal.viewport_sized",
|
|
398
|
+
`${sized.length} element(s) are sized to the viewport: ${list} \u2014 the frame owns the height; a content-sized frame is measured from the content, so a viewport-sized root never shrinks and grows the frame on every re-measure.`,
|
|
399
|
+
"Remove the viewport height \u2014 size to content, never to the viewport. Under fullscreen the frame stretches your root already (centre inside it with `display: flex; flex-direction: column; justify-content: center`); to fill a parent that has a height use `height: 100%` or `flex: 1`."
|
|
400
|
+
)
|
|
401
|
+
];
|
|
402
|
+
}
|
|
263
403
|
var UNIVERSAL_CHECKS = [
|
|
404
|
+
{
|
|
405
|
+
id: "universal.icon_name_known",
|
|
406
|
+
axis: "render",
|
|
407
|
+
values: ALL_RENDER_VALUES,
|
|
408
|
+
run: runIconNameKnown
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
id: "universal.caps_label_invented",
|
|
412
|
+
axis: "render",
|
|
413
|
+
values: ALL_RENDER_VALUES,
|
|
414
|
+
run: runCapsLabelInvented
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
id: "universal.viewport_sized",
|
|
418
|
+
axis: "render",
|
|
419
|
+
values: ALL_RENDER_VALUES,
|
|
420
|
+
run: runViewportSized
|
|
421
|
+
},
|
|
422
|
+
{
|
|
423
|
+
id: "universal.accent_text_ink",
|
|
424
|
+
axis: "render",
|
|
425
|
+
values: ALL_RENDER_VALUES,
|
|
426
|
+
run: runAccentTextInk
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
id: "universal.scoped_surface_owns_ground",
|
|
430
|
+
axis: "render",
|
|
431
|
+
values: ALL_RENDER_VALUES,
|
|
432
|
+
run: runScopedSurfaceOwnsGround
|
|
433
|
+
},
|
|
264
434
|
{
|
|
265
435
|
id: "universal.prop_coverage",
|
|
266
436
|
axis: "render",
|
|
@@ -1063,6 +1233,87 @@ var TOOLING_CHECKS = [
|
|
|
1063
1233
|
}
|
|
1064
1234
|
];
|
|
1065
1235
|
|
|
1236
|
+
// src/evaluation/axis-checks/checks/grid.ts
|
|
1237
|
+
var BOARD_PROP_RX = /^(columns?|lanes?|stages?|lists?|buckets?|swimlanes?)$/i;
|
|
1238
|
+
var BOARD_PROMPT_RX = /\b(kanban|board)\b/i;
|
|
1239
|
+
var BOARD_NAMES = ["columns", "lanes", "stages", "lists", "buckets", "swimlanes"];
|
|
1240
|
+
var LAYOUT_TAG_RX = /<(\/?)(Grid|Row|Stack|Card|Box|Container|ScrollArea|div|section)\b([^<>]*?)>/g;
|
|
1241
|
+
var SIDE_BY_SIDE = /* @__PURE__ */ new Set(["Grid", "Row"]);
|
|
1242
|
+
function boardPropNames(contract) {
|
|
1243
|
+
const propsField = contract?.propsSpec;
|
|
1244
|
+
const properties = propsField?.properties ?? {};
|
|
1245
|
+
return Object.entries(properties).filter(([name, p]) => BOARD_PROP_RX.test(name) && (p?.type === "array" || p?.schema?.type === "array")).map(([name]) => name);
|
|
1246
|
+
}
|
|
1247
|
+
function jsxMapPositions(sourceCode, name) {
|
|
1248
|
+
const rx = new RegExp(
|
|
1249
|
+
`\\b${name}(?:\\?\\.)?\\.map\\(\\s*\\(?\\s*\\w+(?:\\s*,\\s*\\w+)?\\s*\\)?\\s*=>\\s*(?:\\(?\\s*<|\\{[^{}]{0,600}?\\breturn\\s*\\(?\\s*<)`,
|
|
1250
|
+
"g"
|
|
1251
|
+
);
|
|
1252
|
+
return [...sourceCode.matchAll(rx)].map((m) => m.index ?? 0);
|
|
1253
|
+
}
|
|
1254
|
+
function enclosingLayoutTag(sourceCode, pos) {
|
|
1255
|
+
const stack = [];
|
|
1256
|
+
for (const m of sourceCode.slice(0, pos).matchAll(LAYOUT_TAG_RX)) {
|
|
1257
|
+
const closing = m[1] === "/";
|
|
1258
|
+
const name = m[2] ?? "";
|
|
1259
|
+
const attrs = m[3] ?? "";
|
|
1260
|
+
if (closing) {
|
|
1261
|
+
if (stack[stack.length - 1] === name) stack.pop();
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
if (attrs.trimEnd().endsWith("/")) continue;
|
|
1265
|
+
stack.push(name);
|
|
1266
|
+
}
|
|
1267
|
+
return stack[stack.length - 1];
|
|
1268
|
+
}
|
|
1269
|
+
function describeBoardRead(input) {
|
|
1270
|
+
const declared = boardPropNames(input.contract);
|
|
1271
|
+
const names = declared.length > 0 ? declared : BOARD_PROMPT_RX.test(input.originalPrompt) ? [...BOARD_NAMES] : BOARD_NAMES.filter((n) => jsxMapPositions(input.sourceCode, n).length > 0);
|
|
1272
|
+
const perName = names.map((name) => {
|
|
1273
|
+
const positions = jsxMapPositions(input.sourceCode, name);
|
|
1274
|
+
return { name, maps: positions.length, enclosing: positions.map((pos) => enclosingLayoutTag(input.sourceCode, pos) ?? "nothing") };
|
|
1275
|
+
});
|
|
1276
|
+
return { declared, names, perName };
|
|
1277
|
+
}
|
|
1278
|
+
function findStackedBoardColumns(input) {
|
|
1279
|
+
const stacked = [];
|
|
1280
|
+
for (const { name, enclosing } of describeBoardRead(input).perName) {
|
|
1281
|
+
for (const tag of enclosing) if (!SIDE_BY_SIDE.has(tag)) stacked.push([name, tag]);
|
|
1282
|
+
}
|
|
1283
|
+
return stacked;
|
|
1284
|
+
}
|
|
1285
|
+
function runBoardColumnsSideBySide(input) {
|
|
1286
|
+
if (input.compiledCode === null) return [];
|
|
1287
|
+
const standDown = input.designMode === "free";
|
|
1288
|
+
const stacked = standDown ? [] : findStackedBoardColumns(input);
|
|
1289
|
+
if (axisCheckTraceEnabled()) {
|
|
1290
|
+
const line = {
|
|
1291
|
+
...describeBoardRead(input),
|
|
1292
|
+
designMode: input.designMode ?? "constrained",
|
|
1293
|
+
standDown,
|
|
1294
|
+
result: standDown ? "stand-down" : stacked.length > 0 ? "fail" : "pass"
|
|
1295
|
+
};
|
|
1296
|
+
console.log(JSON.stringify({ boardColumnsTrace: line }));
|
|
1297
|
+
}
|
|
1298
|
+
if (stacked.length === 0) return [];
|
|
1299
|
+
const [name, tag] = stacked[0];
|
|
1300
|
+
return [
|
|
1301
|
+
mkIssue(
|
|
1302
|
+
"grid.board_columns_side_by_side",
|
|
1303
|
+
`The board's \`${name}\` are composed under <${tag}> \u2014 a vertical stack of column sections; at md and wider the columns must sit side by side.`,
|
|
1304
|
+
`Wrap the ${name} map in <Grid columns={{ base: 1, md: ${name}.length }} gap="md"> (each column its own <Stack> of cards); never a <Stack> of column sections.`
|
|
1305
|
+
)
|
|
1306
|
+
];
|
|
1307
|
+
}
|
|
1308
|
+
var GRID_CHECKS = [
|
|
1309
|
+
{
|
|
1310
|
+
id: "grid.board_columns_side_by_side",
|
|
1311
|
+
axis: "render",
|
|
1312
|
+
values: ["grid"],
|
|
1313
|
+
run: runBoardColumnsSideBySide
|
|
1314
|
+
}
|
|
1315
|
+
];
|
|
1316
|
+
|
|
1066
1317
|
// src/evaluation/axis-checks/extras.ts
|
|
1067
1318
|
function mkIssue2(subcategory, description, fix, result = "warn") {
|
|
1068
1319
|
return { tier: 0, result, category: "mode", subcategory, description, fix };
|
|
@@ -1152,6 +1403,7 @@ var stepperAdopted = {
|
|
|
1152
1403
|
values: ["multi-step"],
|
|
1153
1404
|
run(input) {
|
|
1154
1405
|
if (input.compiledCode === null) return [];
|
|
1406
|
+
if (input.designMode === "free") return [];
|
|
1155
1407
|
if (/<Stepper[\s/>]/.test(input.sourceCode)) return [];
|
|
1156
1408
|
return [
|
|
1157
1409
|
mkIssue2(
|
|
@@ -1201,6 +1453,7 @@ var REGISTRY = [
|
|
|
1201
1453
|
...WRITES_CHECKS,
|
|
1202
1454
|
...STATE_PAYLOAD_CHECKS,
|
|
1203
1455
|
...TOOLING_CHECKS,
|
|
1456
|
+
...GRID_CHECKS,
|
|
1204
1457
|
...EXTRA_CHECKS
|
|
1205
1458
|
];
|
|
1206
1459
|
|
|
@@ -1214,26 +1467,59 @@ function matches(vector, check) {
|
|
|
1214
1467
|
}
|
|
1215
1468
|
return true;
|
|
1216
1469
|
}
|
|
1217
|
-
|
|
1218
|
-
// src/evaluation/axis-checks/dispatch.ts
|
|
1219
1470
|
function runAxisChecks(classification, input) {
|
|
1220
|
-
|
|
1221
|
-
const axisInput = {
|
|
1471
|
+
const facts = {
|
|
1222
1472
|
sourceCode: input.sourceCode,
|
|
1223
|
-
compiledCode: input.compiledCode,
|
|
1224
1473
|
...input.contract !== void 0 ? { contract: input.contract } : {},
|
|
1225
1474
|
originalPrompt: input.originalPrompt,
|
|
1226
|
-
classification
|
|
1475
|
+
classification,
|
|
1476
|
+
...input.designMode !== void 0 ? { designMode: input.designMode } : {}
|
|
1227
1477
|
};
|
|
1478
|
+
if (input.compiledCode === null) {
|
|
1479
|
+
traceAxisChecksSkipped(facts, "compiledCode null \u2014 no check ran");
|
|
1480
|
+
return [];
|
|
1481
|
+
}
|
|
1482
|
+
const axisInput = { ...facts, compiledCode: input.compiledCode };
|
|
1483
|
+
return runGatedAxisChecks(
|
|
1484
|
+
REGISTRY.filter((check) => matches(classification.vector, check)),
|
|
1485
|
+
axisInput
|
|
1486
|
+
).issues;
|
|
1487
|
+
}
|
|
1488
|
+
function runGatedAxisChecks(checks, input) {
|
|
1228
1489
|
const issues = [];
|
|
1229
|
-
const firedIds =
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
if (
|
|
1233
|
-
|
|
1234
|
-
|
|
1490
|
+
const firedIds = [];
|
|
1491
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1492
|
+
for (const check of checks) {
|
|
1493
|
+
if (seen.has(check.id)) continue;
|
|
1494
|
+
seen.add(check.id);
|
|
1495
|
+
firedIds.push(check.id);
|
|
1496
|
+
issues.push(...check.run(input));
|
|
1235
1497
|
}
|
|
1236
|
-
|
|
1498
|
+
if (axisCheckTraceEnabled()) {
|
|
1499
|
+
const line = {
|
|
1500
|
+
...traceFacts(input),
|
|
1501
|
+
matched: [...firedIds],
|
|
1502
|
+
issues: issues.map((i) => ({ id: i.subcategory ?? i.category, result: i.result }))
|
|
1503
|
+
};
|
|
1504
|
+
console.log(JSON.stringify({ axisCheckTrace: line }));
|
|
1505
|
+
}
|
|
1506
|
+
return { issues, firedIds };
|
|
1507
|
+
}
|
|
1508
|
+
function traceAxisChecksSkipped(facts, note) {
|
|
1509
|
+
if (!axisCheckTraceEnabled()) return;
|
|
1510
|
+
const line = { ...traceFacts(facts), matched: [], issues: [], note };
|
|
1511
|
+
console.log(JSON.stringify({ axisCheckTrace: line }));
|
|
1512
|
+
}
|
|
1513
|
+
function traceFacts(input) {
|
|
1514
|
+
const propsSpec = input.contract?.propsSpec;
|
|
1515
|
+
return {
|
|
1516
|
+
sourceSha256: createHash("sha256").update(input.sourceCode, "utf8").digest("hex"),
|
|
1517
|
+
originalPrompt: input.originalPrompt,
|
|
1518
|
+
designMode: input.designMode ?? "constrained",
|
|
1519
|
+
classification: input.classification.vector,
|
|
1520
|
+
propsSpecKeys: Object.keys(propsSpec ?? {}),
|
|
1521
|
+
propsSpecPropertyKeys: Object.keys(propsSpec?.properties ?? {})
|
|
1522
|
+
};
|
|
1237
1523
|
}
|
|
1238
1524
|
|
|
1239
1525
|
export { EXTRA_CHECKS, REGISTRY, matches, runAxisChecks };
|