@ggui-ai/ui-gen 0.8.0 → 0.10.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 +18 -1
- package/dist/adapters/generation-dispatch.js +819 -1577
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +28 -11
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +5 -3
- package/dist/advanced/index.js +838 -1579
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +109 -3
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.js +17 -4
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +1 -1
- package/dist/check/index.js +11 -1
- package/dist/check/index.js.map +1 -1
- package/dist/compose.js +5 -5
- package/dist/compose.js.map +1 -1
- package/dist/{create-ui-generator-GX7tvbyH.d.ts → create-ui-generator-CF0EL0Li.d.ts} +26 -1
- package/dist/{dispatch-Deo9qzrG.d.ts → dispatch-D75M-OfZ.d.ts} +1 -1
- package/dist/evaluation/axis-checks/index.d.ts +3 -3
- package/dist/evaluation/axis-checks/index.js +133 -1
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +1 -1
- package/dist/evaluation/axis-checks/registry.js +133 -1
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +46 -3
- package/dist/evaluation/index.js +410 -24
- package/dist/evaluation/index.js.map +1 -1
- package/dist/fragments/index.js +5 -5
- package/dist/fragments/index.js.map +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +2 -2
- package/dist/harness/check/runtime-render/index.js +110 -3
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/index.d.ts +5 -126
- package/dist/harness/index.js +292 -32
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.d.ts +1 -1
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.js +17 -3
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +1 -1
- package/dist/harness/runtime.d.ts +17 -1
- package/dist/harness/runtime.js +23 -8
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +1 -1
- package/dist/harness/types-public.js +22 -9
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.js +838 -1579
- package/dist/index.js.map +1 -1
- package/dist/llm-router-BEVtbAb9.d.ts +213 -0
- package/dist/patch.d.ts +1 -1
- package/dist/provider-adapter.d.ts +16 -6
- package/dist/provider-adapter.js.map +1 -1
- package/dist/providers/index.d.ts +54 -99
- package/dist/providers/index.js +13 -8
- package/dist/providers/index.js.map +1 -1
- package/dist/{render-check-CNZjHD5g.d.ts → render-check-BNYGVDJd.d.ts} +1 -1
- package/dist/{types-public-C36k1q6s.d.ts → types-public-DIpjC-OA.d.ts} +1 -1
- package/dist/validation/index.js +2 -2
- package/dist/validation/index.js.map +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +18 -18
- package/src/adapters/generation-dispatch.ts +28 -2
- package/src/adapters/openrouter/client.ts +2 -2
- package/src/adapters/openrouter/types.ts +10 -0
- package/src/boilerplate/generate.ts +10 -2
- package/src/boilerplate/json-schema-ts.ts +22 -2
- package/src/boilerplate/system-prompt.ts +4 -2
- package/src/compile.ts +1 -1
- package/src/contract-context.ts +10 -2
- package/src/create-ui-generator.ts +58 -11
- package/src/design-system-docs.ts +6 -4
- package/src/evaluation/axis-checks/checks/state-merge.ts +1 -1
- package/src/evaluation/axis-checks/checks/state-ui-affordance.ts +162 -0
- package/src/evaluation/axis-checks/checks/universal.ts +39 -0
- package/src/evaluation/axis-checks/registry.ts +2 -0
- package/src/evaluation/index.ts +11 -0
- package/src/evaluation/llm-evaluator.ts +26 -3
- package/src/evaluation/visual-evaluator.ts +49 -66
- package/src/fragments/realtime.ts +3 -3
- package/src/fragments/state.ts +2 -2
- package/src/harness/check/runtime-render/adapter.ts +18 -0
- package/src/harness/check/runtime-render/index.ts +8 -0
- package/src/harness/check/runtime-render/prepare-mockup.ts +14 -0
- package/src/harness/check/runtime-render/production-act-shim.ts +158 -0
- package/src/harness/check/runtime-render/render-check.ts +72 -1
- package/src/harness/coding/init-session.ts +4 -1
- package/src/harness/coding/run-eval-round.ts +67 -5
- package/src/harness/index.ts +1 -1
- package/src/harness/llm-router.ts +451 -27
- package/src/harness/llm-trace-sink.ts +2 -1
- package/src/harness/runtime.ts +15 -0
- package/src/index.ts +5 -5
- package/src/provider-adapter.ts +16 -6
- package/src/providers/bedrock.ts +89 -26
- package/src/providers/index.ts +16 -4
- package/src/tools/render-check.ts +19 -7
- package/src/validation/ui-compiler.ts +2 -2
|
@@ -235,6 +235,31 @@ function runNoPhantomUseState(input) {
|
|
|
235
235
|
}
|
|
236
236
|
return issues;
|
|
237
237
|
}
|
|
238
|
+
function runPropSeedNoResync(input) {
|
|
239
|
+
if (input.compiledCode === null) return [];
|
|
240
|
+
const src = input.sourceCode;
|
|
241
|
+
const issues = [];
|
|
242
|
+
const re = /const\s*\[\s*(\w+)\s*,\s*(\w+)\s*\]\s*=\s*useState(?:<[^>]*>)?\s*\(\s*props\??\.(\w+)/g;
|
|
243
|
+
for (const m of src.matchAll(re)) {
|
|
244
|
+
const [full, stateVar, setter, propName] = m;
|
|
245
|
+
const idx = m.index ?? 0;
|
|
246
|
+
const after = src.slice(idx + full.length);
|
|
247
|
+
if (!new RegExp(`\\b${setter}\\s*\\(`).test(after)) continue;
|
|
248
|
+
const resync = new RegExp(
|
|
249
|
+
`\\[[^\\[\\]]*props\\??\\.${propName}\\b[^\\[\\]]*\\]`
|
|
250
|
+
);
|
|
251
|
+
if (resync.test(src)) continue;
|
|
252
|
+
issues.push(
|
|
253
|
+
mkIssue(
|
|
254
|
+
"universal.prop_seed_no_resync",
|
|
255
|
+
`useState(props.${propName}) seeds "${stateVar}" and mutates it, but no effect depends on [props.${propName}] \u2014 a ggui_amend repaint pushes new props that never reach this display (#480).`,
|
|
256
|
+
`Add \`useEffect(() => ${setter}(props.${propName}), [props.${propName}]);\` so agent repaints re-seed the state, or derive the display directly from props.${propName}.`,
|
|
257
|
+
"warn"
|
|
258
|
+
)
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
return issues;
|
|
262
|
+
}
|
|
238
263
|
var UNIVERSAL_CHECKS = [
|
|
239
264
|
{
|
|
240
265
|
id: "universal.prop_coverage",
|
|
@@ -253,6 +278,12 @@ var UNIVERSAL_CHECKS = [
|
|
|
253
278
|
axis: "render",
|
|
254
279
|
values: ALL_RENDER_VALUES,
|
|
255
280
|
run: runNoPhantomUseState
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
id: "universal.prop_seed_no_resync",
|
|
284
|
+
axis: "render",
|
|
285
|
+
values: ALL_RENDER_VALUES,
|
|
286
|
+
run: runPropSeedNoResync
|
|
256
287
|
}
|
|
257
288
|
];
|
|
258
289
|
|
|
@@ -272,7 +303,7 @@ function runStateSeededFromProps(input) {
|
|
|
272
303
|
mkIssue(
|
|
273
304
|
"state.merge.seeded_from_props",
|
|
274
305
|
`Entity collection "${e.name}" is not seeded from props \u2014 no useState initializer reads props.${e.name}.`,
|
|
275
|
-
`Add \`const [${e.name}, set${cap(e.name)}] = useState(props.${e.name});\` so stream/action updates
|
|
306
|
+
`Add \`const [${e.name}, set${cap(e.name)}] = useState(props.${e.name});\` paired with \`useEffect(() => set${cap(e.name)}(props.${e.name}), [props.${e.name}]);\` so stream/action updates merge into live state AND agent repaints (ggui_amend) re-seed it (#480).`
|
|
276
307
|
)
|
|
277
308
|
);
|
|
278
309
|
}
|
|
@@ -376,6 +407,106 @@ var STATE_MERGE_CHECKS = [
|
|
|
376
407
|
}
|
|
377
408
|
];
|
|
378
409
|
|
|
410
|
+
// src/evaluation/axis-checks/checks/state-ui-affordance.ts
|
|
411
|
+
var STATE_ARIA_OR_ROLE = /aria-(checked|pressed|selected|expanded|current)\s*=|role\s*=/;
|
|
412
|
+
var STATE_PRIMITIVE_IN_SUBTREE = /<(Checkbox|Toggle|Tabs|Accordion)[\s/>]/;
|
|
413
|
+
var SEMANTIC_PRIMITIVES = /* @__PURE__ */ new Set(["Button", "Checkbox", "Toggle", "Link", "MenuItem"]);
|
|
414
|
+
function collectSetters(src) {
|
|
415
|
+
const setters = /* @__PURE__ */ new Set();
|
|
416
|
+
for (const m of src.matchAll(/const\s*\[\s*\w+\s*,\s*(set\w+)\s*\]\s*=\s*useState/g)) {
|
|
417
|
+
setters.add(m[1]);
|
|
418
|
+
}
|
|
419
|
+
return setters;
|
|
420
|
+
}
|
|
421
|
+
function collectHandlers(src, setters) {
|
|
422
|
+
const handlers = /* @__PURE__ */ new Set();
|
|
423
|
+
for (const m of src.matchAll(/const\s+(\w+)\s*=\s*(?:\([^)]*\)|\w+)\s*=>\s*\{?/g)) {
|
|
424
|
+
const body = src.slice(m.index + m[0].length, m.index + m[0].length + 400);
|
|
425
|
+
for (const s of setters) {
|
|
426
|
+
if (body.includes(s)) {
|
|
427
|
+
handlers.add(m[1]);
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
return handlers;
|
|
433
|
+
}
|
|
434
|
+
function attrBlock(src, start) {
|
|
435
|
+
let depth = 0;
|
|
436
|
+
for (let i = start; i < src.length; i++) {
|
|
437
|
+
const c = src[i];
|
|
438
|
+
if (c === "{") depth++;
|
|
439
|
+
else if (c === "}") depth--;
|
|
440
|
+
else if (c === ">" && depth === 0) return { block: src.slice(start, i), end: i };
|
|
441
|
+
}
|
|
442
|
+
return { block: src.slice(start, start + 900), end: start + 900 };
|
|
443
|
+
}
|
|
444
|
+
function onClickValue(block) {
|
|
445
|
+
const m = block.match(/onClick\s*=\s*\{/);
|
|
446
|
+
if (!m || m.index === void 0) return null;
|
|
447
|
+
const open = m.index + m[0].length - 1;
|
|
448
|
+
let depth = 0;
|
|
449
|
+
for (let i = open; i < block.length; i++) {
|
|
450
|
+
if (block[i] === "{") depth++;
|
|
451
|
+
else if (block[i] === "}") {
|
|
452
|
+
depth--;
|
|
453
|
+
if (depth === 0) return block.slice(open + 1, i);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
return block.slice(open + 1);
|
|
457
|
+
}
|
|
458
|
+
function subtree(src, pos, tag) {
|
|
459
|
+
const close = src.indexOf(`</${tag}>`, pos);
|
|
460
|
+
return src.slice(pos, close === -1 ? pos + 700 : close);
|
|
461
|
+
}
|
|
462
|
+
function runStateAriaPresent(input) {
|
|
463
|
+
if (input.compiledCode === null) return [];
|
|
464
|
+
const src = input.sourceCode;
|
|
465
|
+
const setters = collectSetters(src);
|
|
466
|
+
const handlers = collectHandlers(src, setters);
|
|
467
|
+
const issues = [];
|
|
468
|
+
const flaggedLines = /* @__PURE__ */ new Set();
|
|
469
|
+
const localComponents = /* @__PURE__ */ new Set();
|
|
470
|
+
for (const m of src.matchAll(/(?:function\s+([A-Z]\w*)\s*\(|const\s+([A-Z]\w*)\s*=)/g)) {
|
|
471
|
+
localComponents.add(m[1] ?? m[2]);
|
|
472
|
+
}
|
|
473
|
+
for (const m of src.matchAll(/<([A-Za-z][A-Za-z0-9]*)\b/g)) {
|
|
474
|
+
const tag = m[1];
|
|
475
|
+
if (m.index === void 0) continue;
|
|
476
|
+
if (localComponents.has(tag)) continue;
|
|
477
|
+
const { block, end } = attrBlock(src, m.index + m[0].length);
|
|
478
|
+
const clickValue = onClickValue(block);
|
|
479
|
+
if (clickValue === null) continue;
|
|
480
|
+
const mutatesAffordance = [...setters].some((s) => clickValue.includes(s)) || [...handlers].some((h) => new RegExp(`\\b${h}\\b`).test(clickValue)) || // Extracted-subcomponent shape: the toggle handler arrives as an
|
|
481
|
+
// `on[A-Z]…` callback prop and is invoked from onClick — inside a
|
|
482
|
+
// ui-affordance component that IS the affordance mutation.
|
|
483
|
+
/\bon[A-Z]\w*\b/.test(clickValue);
|
|
484
|
+
if (!mutatesAffordance) continue;
|
|
485
|
+
if (SEMANTIC_PRIMITIVES.has(tag)) continue;
|
|
486
|
+
if (STATE_ARIA_OR_ROLE.test(block)) continue;
|
|
487
|
+
if (STATE_PRIMITIVE_IN_SUBTREE.test(subtree(src, end, tag))) continue;
|
|
488
|
+
const line = src.slice(0, m.index).split("\n").length;
|
|
489
|
+
if (flaggedLines.has(line)) continue;
|
|
490
|
+
flaggedLines.add(line);
|
|
491
|
+
issues.push(
|
|
492
|
+
mkIssue(
|
|
493
|
+
"state.ui_affordance.state_aria_present",
|
|
494
|
+
`Line ${line}: <${tag}> toggles the UI affordance from its onClick but exposes no state ARIA \u2014 its checked/selected/expanded state is invisible to assistive technology (styling is the only carrier).`,
|
|
495
|
+
`Add the matching state attribute to the SAME element that carries the onClick: \`role="checkbox"\` + \`aria-checked={\u2026}\` for a toggle row, \`aria-pressed\` for a toggle button, \`aria-selected\` for a selection, \`aria-expanded\` for an open/close affordance \u2014 or replace the hand-rolled control with the state-carrying primitive (Checkbox / Toggle / Tabs / Accordion). \`as={Clickable}\` adds button + keyboard semantics but NOT state.`
|
|
496
|
+
)
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
return issues;
|
|
500
|
+
}
|
|
501
|
+
var STATE_UI_AFFORDANCE_CHECKS = [
|
|
502
|
+
{
|
|
503
|
+
id: "state.ui_affordance.state_aria_present",
|
|
504
|
+
axis: "state",
|
|
505
|
+
values: ["ui-affordance"],
|
|
506
|
+
run: runStateAriaPresent
|
|
507
|
+
}
|
|
508
|
+
];
|
|
509
|
+
|
|
379
510
|
// src/evaluation/axis-checks/checks/realtime.ts
|
|
380
511
|
var REALTIME_ACTIVE = ["merge", "append", "status", "presence", "mixed"];
|
|
381
512
|
function runStreamHandlerPerEvent(input) {
|
|
@@ -1065,6 +1196,7 @@ var EXTRA_CHECKS = [
|
|
|
1065
1196
|
var REGISTRY = [
|
|
1066
1197
|
...UNIVERSAL_CHECKS,
|
|
1067
1198
|
...STATE_MERGE_CHECKS,
|
|
1199
|
+
...STATE_UI_AFFORDANCE_CHECKS,
|
|
1068
1200
|
...REALTIME_CHECKS,
|
|
1069
1201
|
...WRITES_CHECKS,
|
|
1070
1202
|
...STATE_PAYLOAD_CHECKS,
|