@ggui-ai/ui-gen 0.24.0 → 0.25.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.
Files changed (98) hide show
  1. package/dist/{adapter-Du7P_5Fx.d.ts → adapter-Cg_rkpGq.d.ts} +1 -1
  2. package/dist/adapters/generation-dispatch.d.ts +27 -5
  3. package/dist/adapters/generation-dispatch.js +909 -53
  4. package/dist/adapters/generation-dispatch.js.map +1 -1
  5. package/dist/adapters/index.js +3 -1
  6. package/dist/adapters/index.js.map +1 -1
  7. package/dist/advanced/index.d.ts +12 -10
  8. package/dist/advanced/index.js +917 -98
  9. package/dist/advanced/index.js.map +1 -1
  10. package/dist/{axes-CzLEMDeB.d.ts → axes-CKVCzR_x.d.ts} +1 -1
  11. package/dist/bank-CT4eEkta.d.ts +118 -0
  12. package/dist/boilerplate.js +24 -12
  13. package/dist/boilerplate.js.map +1 -1
  14. package/dist/check/index.d.ts +11 -4
  15. package/dist/check/index.js +47 -1
  16. package/dist/check/index.js.map +1 -1
  17. package/dist/classifier/index.d.ts +2 -2
  18. package/dist/compose.d.ts +2 -2
  19. package/dist/{create-ui-generator-GIhzx08x.d.ts → create-ui-generator-DFnnArrv.d.ts} +11 -3
  20. package/dist/{dispatch-BnAH56p4.d.ts → dispatch-CStl9eAw.d.ts} +5 -3
  21. package/dist/evaluation/axis-checks/index.d.ts +5 -5
  22. package/dist/evaluation/axis-checks/index.js +90 -2
  23. package/dist/evaluation/axis-checks/index.js.map +1 -1
  24. package/dist/evaluation/axis-checks/registry.d.ts +3 -3
  25. package/dist/evaluation/axis-checks/registry.js +88 -1
  26. package/dist/evaluation/axis-checks/registry.js.map +1 -1
  27. package/dist/evaluation/index.d.ts +300 -23
  28. package/dist/evaluation/index.js +746 -30
  29. package/dist/evaluation/index.js.map +1 -1
  30. package/dist/evaluation/types.d.ts +9 -1
  31. package/dist/evaluation/types.js.map +1 -1
  32. package/dist/fragments/index.d.ts +3 -3
  33. package/dist/harness/check/runtime-render/index.d.ts +5 -5
  34. package/dist/harness/index.d.ts +4 -4
  35. package/dist/harness/index.js +33 -15
  36. package/dist/harness/index.js.map +1 -1
  37. package/dist/harness/result-types.d.ts +3 -3
  38. package/dist/harness/runtime.d.ts +10 -4
  39. package/dist/harness/runtime.js +26 -14
  40. package/dist/harness/runtime.js.map +1 -1
  41. package/dist/harness/types-public.d.ts +3 -3
  42. package/dist/harness/types-public.js +33 -15
  43. package/dist/harness/types-public.js.map +1 -1
  44. package/dist/harness/validator-trace-sink.d.ts +3 -3
  45. package/dist/hash.d.ts +1 -1
  46. package/dist/index.d.ts +25 -9
  47. package/dist/index.js +926 -101
  48. package/dist/index.js.map +1 -1
  49. package/dist/{llm-router-DwwUK1bz.d.ts → llm-router-nfO7wPec.d.ts} +3 -1
  50. package/dist/patch.d.ts +3 -3
  51. package/dist/policy.d.ts +1 -1
  52. package/dist/tools/get-primitives-ts.d.ts +1 -1
  53. package/dist/tools/get-primitives-ts.js +1 -1
  54. package/dist/tools/get-primitives-ts.js.map +1 -1
  55. package/dist/{types-BOvHNG7K.d.ts → types-Dh1s4K9j.d.ts} +1 -1
  56. package/dist/{types-public-Bk6d1WLN.d.ts → types-public-BJTLpzWn.d.ts} +134 -7
  57. package/dist/validation/index.d.ts +1 -1
  58. package/dist/validation/index.js +1 -1
  59. package/dist/validation/index.js.map +1 -1
  60. package/dist/workflows.d.ts +3 -3
  61. package/package.json +12 -12
  62. package/src/adapters/generation-dispatch.ts +36 -2
  63. package/src/adapters/tools.ts +2 -1
  64. package/src/boilerplate/free-design-prompt.ts +1 -1
  65. package/src/boilerplate/generate.ts +26 -1
  66. package/src/boilerplate/hard-sections.ts +13 -13
  67. package/src/boilerplate/system-prompt.ts +1 -1
  68. package/src/check/index.ts +1 -0
  69. package/src/check/sample-props.ts +63 -0
  70. package/src/coding-agent/tools.ts +4 -1
  71. package/src/create-harness.ts +3 -3
  72. package/src/create-ui-generator.ts +20 -1
  73. package/src/evaluation/__fixtures__/png.ts +100 -0
  74. package/src/evaluation/axis-checks/checks/state-merge.ts +1 -1
  75. package/src/evaluation/axis-checks/checks/universal.ts +111 -0
  76. package/src/evaluation/axis-checks/dispatch.ts +4 -1
  77. package/src/evaluation/criteria/bank.ts +85 -0
  78. package/src/evaluation/criteria/context.ts +52 -0
  79. package/src/evaluation/criteria/resolve.ts +159 -0
  80. package/src/evaluation/criteria/select.ts +79 -0
  81. package/src/evaluation/index.ts +23 -0
  82. package/src/evaluation/ink-extent.ts +200 -0
  83. package/src/evaluation/theme-css.ts +12 -5
  84. package/src/evaluation/types-public.ts +130 -3
  85. package/src/evaluation/types.ts +9 -0
  86. package/src/evaluation/visual-evaluator.ts +636 -30
  87. package/src/harness/coding/generate-task-runner.ts +3 -0
  88. package/src/harness/coding/run-coding-turn.ts +7 -3
  89. package/src/harness/coding/run-eval-round.ts +19 -0
  90. package/src/harness/runtime.ts +5 -0
  91. package/src/harness-tool-names.ts +38 -0
  92. package/src/index.ts +12 -0
  93. package/src/run-check.ts +2 -0
  94. package/src/tools/get-primitives-ts.ts +1 -1
  95. package/src/tools/get-wire.ts +1 -1
  96. package/src/tools/render-check.ts +0 -60
  97. package/src/tools.ts +11 -1
  98. package/src/validation/primitives.ts +1 -1
@@ -1,20 +1,23 @@
1
- import { C as CanvasJudgeRecord, E as EvalIssue, V as VisualEvalSummary, d as VisualCoverage } from '../types-public-Bk6d1WLN.js';
2
- export { A as AxisCheck, a as AxisCheckInput, e as CRITERIA, f as CanvasVisualSummary, g as ContractFeedbackRecord, h as CriterionCoverage, i as CriterionRunStatus, D as DEFAULT_QUALITY_CONFIG, j as EvalCategory, k as EvalCriterion, l as EvalOutcome, b as EvalResult, c as EvalTier, L as LLM_EVAL_STATIC_CRITERIA, n as Priority, Q as QualityConfig, o as QualityMode, p as buildCodingCriteriaSummary, q as criteriaFor, r as getActionableIssues, s as getCriteriaByPriority, t as getCriterionById, u as getLLMCriteria, v as isBlocked, m as matches, w as notApplicableCoverage, x as priorityForIssue } from '../types-public-Bk6d1WLN.js';
1
+ import { C as CriteriaContext, d as CriteriaChroma, e as CanvasJudgeRecord, f as CriteriaBlock, g as CanvasPresentationOutcome, h as CanvasHostPresentation, E as EvalIssue, V as VisualEvalSummary, i as VisualCoverage, j as CriteriaSelection } from '../types-public-BJTLpzWn.js';
2
+ export { A as AxisCheck, a as AxisCheckInput, k as CRITERIA, l as CanvasVisualSummary, n as ContractFeedbackRecord, o as CriterionCoverage, p as CriterionRunStatus, D as DEFAULT_QUALITY_CONFIG, q as EvalCategory, r as EvalCriterion, s as EvalOutcome, b as EvalResult, c as EvalTier, H as HostInlineFrame, t as HostPresentationIgnoredReason, L as LLM_EVAL_STATIC_CRITERIA, u as Priority, Q as QualityConfig, v as QualityMode, w as buildCodingCriteriaSummary, x as criteriaFor, y as getActionableIssues, z as getCriteriaByPriority, B as getCriterionById, F as getLLMCriteria, G as isBlocked, m as matches, I as notApplicableCoverage, J as priorityForIssue } from '../types-public-BJTLpzWn.js';
3
3
  import * as _anthropic_ai_claude_agent_sdk from '@anthropic-ai/claude-agent-sdk';
4
4
  import { McpServerConfig } from '@anthropic-ai/claude-agent-sdk';
5
- import { EvaluationContext, EvaluationConfig, QualityMetadata, EvaluationResult, EvaluationIssue } from './types.js';
5
+ import { EvaluationContext, EvaluationConfig, QualityMetadata, EvaluationResult, EvaluationIssue, CriteriaAnswer } from './types.js';
6
6
  export { DEFAULT_EVAL_MAX_ROUNDS, DimensionScores, MAX_EVAL_ROUNDS_HARD_LIMIT } from './types.js';
7
- export { R as RunAxisChecksInput, r as runAxisChecks } from '../dispatch-BnAH56p4.js';
8
- import { A as AgentConfig, L as LLMResponse } from '../llm-router-DwwUK1bz.js';
7
+ export { R as RunAxisChecksInput, r as runAxisChecks } from '../dispatch-CStl9eAw.js';
8
+ import { A as AgentConfig, L as LLMResponse } from '../llm-router-nfO7wPec.js';
9
9
  import { G as GenerationProfileInput } from '../styling-profile-CxfvV48g.js';
10
+ import { C as CriteriaBank } from '../bank-CT4eEkta.js';
11
+ export { B as BankRow, a as CriteriaScope, b as bankRows, c as criteriaBankSchema, p as parseCriteriaBank } from '../bank-CT4eEkta.js';
12
+ import { DataContract, JsonObject, AppTheme } from '@ggui-ai/protocol';
13
+ import { C as Classification } from '../axes-CKVCzR_x.js';
10
14
  import { LaunchOptions } from 'puppeteer-core';
11
15
  import { C as CanvasClass, g as CanvasViewport } from '../design-mode-DLufhrNp.js';
12
16
  export { a as CANVAS_BREAKPOINTS, b as CANVAS_CLASSES, c as CANVAS_DESCRIPTORS, d as CANVAS_VIEWPORTS, e as CanvasDescriptor, f as CanvasDisplayMode, j as canvasDisplayModeForShell, k as canvasForRendering, l as canvasForViewportWidth, m as describeCanvas } from '../design-mode-DLufhrNp.js';
13
- import { AppTheme } from '@ggui-ai/protocol';
14
17
  import '@ggui-ai/mcp-server-core';
15
- import '../axes-CzLEMDeB.js';
16
- import '../types-BOvHNG7K.js';
18
+ import '../types-Dh1s4K9j.js';
17
19
  import '../llm.js';
20
+ import 'zod';
18
21
 
19
22
  /**
20
23
  * Options for running the evaluation loop.
@@ -186,6 +189,26 @@ declare function extractCompiledCode(messages: SdkMessage[]): string | undefined
186
189
  */
187
190
  declare function extractSourceCode(messages: SdkMessage[]): string | undefined;
188
191
 
192
+ /**
193
+ * The selector's inputs for one card — ggui#1436. Every key here is hashed into `criteriaSetId`
194
+ * and STORED in the block (the CTO's A1), so a stored verdict reproduces its own set from the
195
+ * record alone. `canvas` is added per canvas inside the judge; the rest is the harness's.
196
+ */
197
+
198
+ /** Read the theme's chroma off its tokens; `unknown` when no primary is named. */
199
+ declare function chromaOfCssTokens(cssTokens: string | undefined): CriteriaChroma;
200
+ interface CriteriaContextSources {
201
+ readonly classification: Classification;
202
+ readonly contract: DataContract | undefined;
203
+ readonly cssTokens: string | undefined;
204
+ readonly profile: GenerationProfileInput | undefined;
205
+ readonly shell: string;
206
+ readonly kind?: string;
207
+ }
208
+ /** The context minus `canvas` — the judge fills that per canvas. */
209
+ type CriteriaContextInput = Omit<CriteriaContext, 'canvas'>;
210
+ declare function criteriaContextFor(src: CriteriaContextSources): CriteriaContextInput;
211
+
189
212
  interface JudgeDesignIdentity {
190
213
  /** Absolute path of the design `src` tree the judge bundled against. */
191
214
  readonly src: string;
@@ -260,6 +283,14 @@ interface VisualEvalConfig {
260
283
  * `viewport` all carry that same integer box.
261
284
  */
262
285
  canvasViewports?: Partial<Readonly<Record<CanvasClass, CanvasViewport>>>;
286
+ /**
287
+ * ggui#1492 — how a host presents each canvas, as data the caller supplies (a lane that knows its host). Keyed by
288
+ * canvas; a canvas without an entry is judged exactly as before (the generic stand-in round the inline card, the
289
+ * scrim under a panel). The box stays in {@link canvasViewports}. An entry this judge cannot use (a colour that is
290
+ * not `#rrggbb`, a number out of range, a frame on a canvas that is not the inline card) is ignored for its canvas,
291
+ * said once in the log, never partly applied.
292
+ */
293
+ hostPresentations?: Partial<Readonly<Record<CanvasClass, CanvasHostPresentation>>>;
263
294
  /**
264
295
  * Optional provider-routing override — see
265
296
  * `AgentConfig.routeOverride`. Threaded onto the agent this
@@ -292,6 +323,14 @@ interface VisualEvalConfig {
292
323
  */
293
324
  onRetry?: AgentConfig['onRetry'];
294
325
  }
326
+ /**
327
+ * ggui#1436 — what the report-only criteria call spent. Kept APART from the scoring calls' `inputTokens` /
328
+ * `outputTokens`: those price the judgement a caller may meter, and the criteria call is a measurement beside it.
329
+ */
330
+ interface CriteriaCallTokens {
331
+ readonly inputTokens: number;
332
+ readonly outputTokens: number;
333
+ }
295
334
  /** One canvas's verdict — screenshot + judge score at that class's viewport. */
296
335
  interface CanvasVisualResult {
297
336
  canvas: CanvasClass;
@@ -311,32 +350,91 @@ interface CanvasVisualResult {
311
350
  /** `contentHeight > viewport.height` — a measurement; what it MEANS is {@link canvasFitPolicy}'s. */
312
351
  overflow: boolean;
313
352
  /** How `score` was reached — always present (ggui#1072). */
353
+ /**
354
+ * ggui#1120 — how far down the capture anything was painted (the last inked row over the measured
355
+ * region's height, read against the capture's dominant colour, inside a drawn panel's chrome); `0`
356
+ * is the blank the judge fails, `null` an unreadable capture.
357
+ */
358
+ inkRatio: number | null;
314
359
  judge: CanvasJudgeRecord;
315
360
  /** How the judge composed the mount (ggui#1100): `'fill'` on every fullscreen canvas, absent on the inline card. */
316
361
  fit?: 'fill';
317
362
  /** ggui#1195 — `true` when the order DECLARED this canvas's box (`config.canvasViewports` carried an entry), whatever its value. */
318
363
  declared?: true;
364
+ /** ggui#1436 — the typed criteria block, when a bank was configured. */
365
+ criteria?: CriteriaBlock;
366
+ /** ggui#1436 — the criteria call's own spend, when one was asked and answered; never inside the canvas's scoring tokens. */
367
+ criteriaTokens?: CriteriaCallTokens;
368
+ /** ggui#1492 — what the judge did with this canvas's host presentation (drawn, or ignored and why), when one was supplied. */
369
+ presentation?: CanvasPresentationOutcome;
319
370
  }
320
371
  /** How a canvas is captured for the judge and what an overflow means there (ggui#1027). */
321
- type CaptureMode = 'viewport' | 'full-page';
372
+ type CaptureMode = 'viewport' | 'full-page' | 'natural';
322
373
  interface CanvasFitPolicy {
323
- /** `viewport` = the judge sees the box the user sees; `full-page` = the whole scrolled document. */
374
+ /**
375
+ * `viewport` = the whole box; `full-page` = the whole scrolled document; `natural` (ggui#1475) = the
376
+ * card at its OWN height, clipped to its extent and capped at the box — the inline card a host sizes
377
+ * to its content, on the host's ground ({@link JUDGE_GROUND_MARGIN_PX}).
378
+ */
324
379
  readonly capture: CaptureMode;
325
380
  /** The verdict an overflow earns on this canvas. */
326
381
  readonly overflow: 'fail' | 'warn' | 'none';
327
382
  }
328
383
  /**
329
- * The inline chat card is a BOX — the bubble bounds the component and it
330
- * does not scroll — so the judge captures the viewport (a 1289 px hello on
331
- * a 640 px card was scored 86 from a full-page capture that showed the
332
- * judge what no user sees) and an overflow is a critical layout issue that
333
- * fails the canvas. A phone's first screen may scroll, so the overflow is
334
- * reported as a major issue and the score stands. Pages (`md`/`lg`/`xl`)
335
- * scroll by design: measured, never judged.
384
+ * The inline chat card takes its NATURAL height under a ceiling (ggui#1475):
385
+ * an MCP Apps host sizes the inline frame to the card's content
386
+ * (`ui/notifications/size-changed`, auto-resize) up to its maximum, so the
387
+ * visitor sees the card and nothing under it. The judge captures exactly
388
+ * that — the card's own extent on the host's ground, capped at the box — and
389
+ * never the box's remainder (a fixed 640 px capture scored every hello
390
+ * against a void no visitor sees). The box stays the ceiling: content taller
391
+ * than it is a critical layout issue that fails the canvas (a 1289 px hello
392
+ * on a 640 px card was scored 86 from a full-page capture that showed the
393
+ * judge what no user sees). A phone's first screen may scroll, so the
394
+ * overflow is reported as a major issue and the score stands. Pages
395
+ * (`md`/`lg`/`xl`) scroll by design: measured, never judged.
336
396
  */
337
397
  declare function canvasFitPolicy(canvas: CanvasClass): CanvasFitPolicy;
398
+ /**
399
+ * How far in from a panelled page's edges the ink is read (ggui#1120): past the panel's gap, its
400
+ * largest rounded corner (the `round` bucket, 24 px — the scrim shows through the corner) and its
401
+ * 1 px hairline, so the host's chrome never counts as paint. The card's own inset is 16 px, so the
402
+ * band skipped inside the card is 25 px of a canvas — reported ratios are over the region.
403
+ */
404
+ declare const JUDGE_INK_INSET_PX: number;
405
+ /**
406
+ * The host ground round a naturally-captured inline card (ggui#1475): the card is mounted this far in
407
+ * from the page's edges and captured with this margin, so its edge and radius are read against the
408
+ * host surface — the page's scrim ground, never the card's own. The design's one gap (the panel's).
409
+ */
410
+ declare const JUDGE_GROUND_MARGIN_PX: 16;
411
+ /**
412
+ * The bounds a host frame must meet to be drawn (ggui#1492), exported so a lane's reader applies exactly the frames
413
+ * this judge draws: an entry the reader accepts and the judge ignores would be echoed as applied while never drawn.
414
+ */
415
+ declare const HOST_COLOUR_PATTERN: RegExp;
416
+ declare const HOST_FRAME_BOUNDS: {
417
+ readonly ringWidthPx: {
418
+ readonly min: 0;
419
+ readonly max: 8;
420
+ };
421
+ readonly ringAlpha: {
422
+ readonly min: 0;
423
+ readonly max: 1;
424
+ };
425
+ readonly radiusPx: {
426
+ readonly min: 0;
427
+ readonly max: 64;
428
+ };
429
+ readonly minHeightPx: {
430
+ readonly min: 0;
431
+ readonly max: 2560;
432
+ };
433
+ };
338
434
  /** The deterministic fit issue — one per overflowing canvas, in the judge's issue shape so it rides the same channel. */
339
435
  declare function canvasOverflowIssue(canvas: CanvasClass, viewport: CanvasViewport, contentHeight: number, verdict: 'fail' | 'warn'): EvaluationIssue;
436
+ /** ggui#1120 — the deterministic blank: the capture is one flat colour, so the component mounted and painted nothing. */
437
+ declare function canvasBlankIssue(canvas: CanvasClass, viewport: CanvasViewport): EvaluationIssue;
340
438
  /**
341
439
  * `runVisualEvaluation`'s result. Identical to `EvaluationResult` when
342
440
  * `config.canvases` is unset; with canvases set, `canvases` holds the
@@ -345,6 +443,11 @@ declare function canvasOverflowIssue(canvas: CanvasClass, viewport: CanvasViewpo
345
443
  */
346
444
  interface VisualEvaluationResult extends EvaluationResult {
347
445
  canvases?: CanvasVisualResult[];
446
+ /**
447
+ * ggui#1436 — the criteria calls' spend across canvases, when any was asked and answered. `inputTokens` /
448
+ * `outputTokens` stay the SCORING calls' alone, so a cost read off them never includes the report-only block.
449
+ */
450
+ criteriaTokens?: CriteriaCallTokens;
348
451
  /** The design tree the judge painted with (ggui#1042) — present on every per-canvas judgement. */
349
452
  design?: JudgeDesignIdentity;
350
453
  /** The mode `cssTokens` were composed in, when the caller said (ggui#1076). */
@@ -364,6 +467,11 @@ interface VisualEvalContext {
364
467
  cssTokens?: string;
365
468
  /** The app's generation profile (#991) — judged relative to, never against. */
366
469
  profile?: GenerationProfileInput;
470
+ /** ggui#1436 — a criteria bank and the card's context; the judge selects per canvas and answers report-only. */
471
+ criteria?: {
472
+ readonly bank: CriteriaBank;
473
+ readonly context: CriteriaContextInput;
474
+ };
367
475
  }
368
476
  /**
369
477
  * The `@ggui-ai/design` package root — resolved by MODULE ID, never by counting
@@ -380,6 +488,13 @@ interface VisualEvalContext {
380
488
  * hoisted — and the receipt keeps working inside the image.
381
489
  */
382
490
  declare function resolveDesignPackageDir(): string;
491
+ /** A screenshot's region in page px (puppeteer's `clip`). */
492
+ interface ScreenshotClip {
493
+ readonly x: number;
494
+ readonly y: number;
495
+ readonly width: number;
496
+ readonly height: number;
497
+ }
383
498
  /** The page surface the capture uses — a structural subset of puppeteer's `Page`. */
384
499
  interface ScreenshotPage {
385
500
  setContent(html: string, options: {
@@ -398,6 +513,7 @@ interface ScreenshotPage {
398
513
  screenshot(options: {
399
514
  type: 'png';
400
515
  fullPage: boolean;
516
+ clip?: ScreenshotClip;
401
517
  }): Promise<Uint8Array>;
402
518
  }
403
519
  /** The browser surface the capture uses — a structural subset of puppeteer's `Browser`. */
@@ -446,13 +562,22 @@ interface ScreenshotAttempt {
446
562
  readonly reason?: string;
447
563
  /** The document's scroll height at the viewport (ggui#1027); `null` when unmeasurable. */
448
564
  readonly contentHeight: number | null;
565
+ /** ggui#1475 — a natural capture's horizontal overflow: how many px the card's content runs past its width; absent on every other capture. */
566
+ readonly overflowX?: number | null;
449
567
  }
450
568
  /** The expression the fit measurement evaluates in the page — the taller of the two scroll heights. */
451
569
  declare const CONTENT_HEIGHT_EXPRESSION = "Math.max(document.documentElement.scrollHeight, document.body ? document.body.scrollHeight : 0)";
570
+ /** The stand-in page's card height ({@link cardHeightExpression} at the stand-in's pad). */
571
+ declare const CARD_HEIGHT_EXPRESSION: string;
572
+ /** ggui#1492 — a natural capture's geometry: the page's pad per side, and the host's floor when it has one. */
573
+ interface NaturalCaptureOptions {
574
+ readonly padPx: number;
575
+ readonly floorPx?: number;
576
+ }
452
577
  declare function captureScreenshotDetailed(html: string, viewport?: {
453
578
  width: number;
454
579
  height: number;
455
- }, deps?: ScreenshotDeps, capture?: CaptureMode): Promise<ScreenshotAttempt>;
580
+ }, deps?: ScreenshotDeps, capture?: CaptureMode, natural?: NaturalCaptureOptions): Promise<ScreenshotAttempt>;
456
581
  declare function captureScreenshot(html: string, viewport?: {
457
582
  width: number;
458
583
  height: number;
@@ -485,7 +610,7 @@ declare const VISUAL_JUDGE_MAX_OUTPUT_TOKENS = 4096;
485
610
  */
486
611
  declare const VISUAL_JUDGE_PROMPT_VERSION = "v2-bounded-issues";
487
612
  declare const VISUAL_JUDGE_PROMPT_DIGEST: string;
488
- declare function callMultimodalLLM(config: VisualEvalConfig, model: string, prompt: string, screenshot: Buffer, originalPrompt: string, profileBlock?: string): Promise<LLMResponse>;
613
+ declare function callMultimodalLLM(config: VisualEvalConfig, model: string, prompt: string, screenshot: Buffer, originalPrompt: string, profileBlock?: string, criteriaBlock?: string): Promise<LLMResponse>;
489
614
  /**
490
615
  * Run visual evaluation on a compiled component.
491
616
  *
@@ -513,6 +638,58 @@ declare function runVisualEvaluation(context: VisualEvalContext, config: VisualE
513
638
  declare function runVisualEvaluationDetailed(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvalDetailed>;
514
639
  /** The per-canvas verdicts without the PNGs — what the harness stamps on `EvalResult.visual`. */
515
640
  declare function summarizeVisualResult(result: VisualEvaluationResult): VisualEvalSummary | undefined;
641
+ /** One stored capture to judge: the frame the judge saw at capture time, plus what the capture measured. */
642
+ interface StoredCaptureInput {
643
+ readonly canvas: CanvasClass;
644
+ /** The capture as saved (`canvas-<class>.png`). */
645
+ readonly png: Buffer;
646
+ /** The box the capture was taken at — the class box, or the declared one. */
647
+ readonly viewport: CanvasViewport;
648
+ /** The document's scroll height the capture recorded; `null` when it did not. */
649
+ readonly contentHeight: number | null;
650
+ readonly originalPrompt: string;
651
+ readonly profile?: GenerationProfileInput;
652
+ /** ggui#1436 — the bank and the card's context; absent = today's judge, no block. */
653
+ readonly criteria?: {
654
+ readonly bank: CriteriaBank;
655
+ readonly context: CriteriaContextInput;
656
+ };
657
+ /** The props the capture was rendered with — handed to the criteria block for the rows whose evidence names props. */
658
+ readonly sampleProps?: JsonObject;
659
+ }
660
+ interface StoredCaptureVerdict {
661
+ readonly canvas: CanvasClass;
662
+ readonly viewport: CanvasViewport;
663
+ readonly score: number;
664
+ readonly passed: boolean;
665
+ readonly issues: EvaluationIssue[];
666
+ readonly judge: CanvasJudgeRecord;
667
+ readonly contentHeight: number | null;
668
+ readonly overflow: boolean;
669
+ readonly inkRatio: number | null;
670
+ readonly criteria?: CriteriaBlock;
671
+ /** The scoring calls' spend. */
672
+ readonly inputTokens: number;
673
+ readonly outputTokens: number;
674
+ /** ggui#1436 — the report-only criteria call's spend, apart from the scoring calls'; absent when none was asked or answered. */
675
+ readonly criteriaTokens?: CriteriaCallTokens;
676
+ }
677
+ type StoredCaptureOutcome = {
678
+ readonly kind: 'ok';
679
+ readonly verdict: StoredCaptureVerdict;
680
+ } | {
681
+ readonly kind: 'unavailable';
682
+ readonly reason: string;
683
+ };
684
+ /**
685
+ * Judge a STORED capture exactly as the per-canvas leg judges a fresh one — the same K scoring calls on the
686
+ * same frame, the same median, the same fit and blank verdicts, the same report-only criteria call — without
687
+ * rendering.
688
+ * This is the calibration's path (ggui#1438): the frame his eye marks is the frame the judge saw, and a
689
+ * re-judge costs judge tokens only. Fit reads the capture's recorded `contentHeight`; ink is read off the
690
+ * PNG inside the canvas's chrome, as at capture.
691
+ */
692
+ declare function judgeStoredCapture(input: StoredCaptureInput, config: VisualEvalConfig, deps?: Pick<VisualEvalDeps, 'judge'>): Promise<StoredCaptureOutcome>;
516
693
 
517
694
  /** What the harness's eval round consumes from the visual leg. */
518
695
  interface VisualEvalOutcome {
@@ -537,13 +714,113 @@ interface VisualEvalOutcome {
537
714
  */
538
715
  declare function runVisualEval(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvalOutcome>;
539
716
 
717
+ /** A channel difference at or below this is the same colour (anti-aliasing and compositing noise). */
718
+ declare const INK_TOLERANCE = 8;
719
+ interface PixelRegion {
720
+ readonly x: number;
721
+ readonly y: number;
722
+ readonly width: number;
723
+ readonly height: number;
724
+ }
725
+ interface InkExtent {
726
+ /** `(lastInkRow + 1) / region.height`, rounded to 3 places; `0` when nothing differs from the ground. */
727
+ readonly ratio: number;
728
+ /** The last region row (0-based from the region's top) carrying ink; `null` when there is none — the blank. */
729
+ readonly lastInkRow: number | null;
730
+ /** The region read, in image px. */
731
+ readonly region: PixelRegion;
732
+ /** The dominant colour the ink was read against, `[r, g, b]`. */
733
+ readonly ground: readonly [number, number, number];
734
+ }
735
+ /** Why a capture could not be read — reported, never mistaken for a blank. */
736
+ interface InkUnreadable {
737
+ readonly reason: string;
738
+ }
739
+ interface DecodedImage {
740
+ readonly width: number;
741
+ readonly height: number;
742
+ readonly channels: 3 | 4;
743
+ /** Row-major, `channels` bytes per pixel, scanline filters undone. */
744
+ readonly pixels: Uint8Array;
745
+ }
746
+ /** The PNG subset the judge's browser writes: 8-bit RGB (colour type 2) or RGBA (6), not interlaced. */
747
+ declare function decodePng(png: Uint8Array): DecodedImage | InkUnreadable;
748
+ /**
749
+ * The ink extent of a capture, read `insetPx` in from every edge — the judge's inset skips a host
750
+ * panel's gap, rounded corners and hairline ({@link JUDGE_INK_INSET_PX}); `0` reads the whole image.
751
+ */
752
+ declare function readInkExtent(png: Uint8Array, insetPx?: number): InkExtent | InkUnreadable;
753
+
540
754
  /**
541
755
  * The stylesheet a visual judge renders under for an app: the app's theme
542
756
  * composed the way the runtime composes it (`composeThemeCss`, layer `page`
543
757
  * — one composition, never a second), so a judged canvas paints the tokens a
544
- * visitor's page paints. Absent theme ⇒ the design's default tokens,
545
- * byte-for-byte what the judge used before.
758
+ * visitor's page paints. `themeId` is the registered ladder the app's theme
759
+ * sits on (the runtime's base layer); an unknown id composes the default
760
+ * ladder. Neither given ⇒ the design's default tokens, byte-for-byte what the
761
+ * judge used before.
762
+ */
763
+ declare function cssTokensForAppTheme(theme: AppTheme | undefined, mode?: 'light' | 'dark', themeId?: string): string;
764
+
765
+ /** Bump when a selection rule changes: it is hashed into every `criteriaSetId`. */
766
+ declare const CRITERIA_SELECTOR_VERSION = "selector@2";
767
+ /** The context as one string, keys sorted at every level — what the id hashes and what the record stores. */
768
+ declare function canonicalCriteriaContext(ctx: CriteriaContext): string;
769
+ /** sha256(bank version | selector version | canonical context), 16 hex — a label at this scale, not a security digest. */
770
+ declare function criteriaSetIdFor(bankVersion: string, ctx: CriteriaContext): string;
771
+ interface CriteriaSelectionResult {
772
+ readonly criteriaSetId: string;
773
+ readonly selection: CriteriaSelection[];
774
+ }
775
+ /**
776
+ * Select the bank's rows for one card. The bank-level `applies` gate is read first (canvases always;
777
+ * kind only when the caller named one and the bank names kinds other than `*`); then each row's
778
+ * `scope`. An empty scope is `static`; a matched scope is `context` with the keys that matched.
779
+ */
780
+ declare function selectCriteria(bank: CriteriaBank, ctx: CriteriaContext): CriteriaSelectionResult;
781
+
782
+ /**
783
+ * From K judge answers and the capture's measurements to one `CriteriaBlock` — ggui#1436.
784
+ *
785
+ * The judge is asked every `evaluation: judge` row (this block IS their implementation; the row's
786
+ * `status` is carried on the verdict as the author wrote it). An `instrument` row is answered by a
787
+ * measurement the capture already ran when its status is `live` and a binding exists; otherwise it
788
+ * reads `n/a` with the reason from `status`. A `human` row reads `n/a` for the judge. K-majority per
789
+ * id; a tie or an unanswered id reads `n/a` (the CTO's A2) — a `must` at `n/a` is never a pass when
790
+ * a gate later reads the set.
546
791
  */
547
- declare function cssTokensForAppTheme(theme: AppTheme | undefined, mode?: 'light' | 'dark'): string;
548
792
 
549
- export { CONTENT_HEIGHT_EXPRESSION, CanvasClass, type CanvasFitPolicy, CanvasJudgeRecord, CanvasViewport, type CanvasVisualResult, type CaptureMode, type ChromiumProvider, EvalIssue, type EvaluateScoreInput, EvaluationConfig, EvaluationContext, EvaluationIssue, type EvaluationLoopOptions, type EvaluationLoopResult, EvaluationResult, type JudgeDesignIdentity, QualityMetadata, type ScreenshotAttempt, type ScreenshotBrowser, type ScreenshotDeps, type ScreenshotLauncher, type ScreenshotPage, type SdkMessage, VISUAL_EVAL_PROMPT, VISUAL_JUDGE_MAX_OUTPUT_TOKENS, VISUAL_JUDGE_PROMPT_DIGEST, VISUAL_JUDGE_PROMPT_VERSION, type VisualEvalConfig, type VisualEvalContext, type VisualEvalDeps, type VisualEvalDetailed, type VisualEvalOutcome, VisualEvalSummary, type VisualEvaluationResult, buildFixPrompt, callMultimodalLLM, canvasFitPolicy, canvasOverflowIssue, captureScreenshot, captureScreenshotDetailed, computeEvaluationScore, createEvaluationToolsServer, cssTokensForAppTheme, designTreeSha256, extractCompiledCode, extractCompiledCodeFromMessage, extractEvalResult, extractSourceCode, extractSourceCodeFromMessage, extractToolResultTexts, getEvaluatorSystemPrompt, judgeDesignIdentity, resetJudgeDesignIdentityCache, resolveDesignPackageDir, resolveLaunchOptions, runEvaluation, runEvaluationLoop, runVisualEval, runVisualEvaluation, runVisualEvaluationDetailed, summarizeVisualResult };
793
+ /** The instruments the capture runs today, by the bank ids they answer (v1 binding; a bank field may replace it). */
794
+ declare const INSTRUMENT_BY_ID: Readonly<Record<string, 'fit' | 'fill'>>;
795
+ interface CriteriaMeasurements {
796
+ readonly overflow: boolean;
797
+ readonly contentHeight: number | null;
798
+ readonly viewportHeight: number;
799
+ readonly inkRatio: number | null;
800
+ }
801
+ declare function resolveCriteriaBlock(args: {
802
+ readonly bank: CriteriaBank;
803
+ readonly context: CriteriaContext;
804
+ readonly selected: CriteriaSelectionResult;
805
+ readonly answers: readonly CriteriaAnswer[][];
806
+ readonly measurements: CriteriaMeasurements;
807
+ }): CriteriaBlock;
808
+ /** The judge's prompt block for the selected `judge` rows; empty when none is selected. */
809
+ /** The capture the judge is handed: its canvas class and the box it was taken at (the class box, or a declared one). */
810
+ interface CriteriaJudgeFrame {
811
+ readonly canvas: CriteriaContext['canvas'];
812
+ readonly width: number;
813
+ readonly height: number;
814
+ /** ggui#1492 — the host whose presentation framed this canvas (e.g. "a chat widget, inline, reference theme"); absent ⇒ the judge's own stand-in. */
815
+ readonly hostLabel?: string;
816
+ }
817
+ /** What the block carries besides the selected rows: the frame's box, and the props the card was rendered with. */
818
+ interface CriteriaJudgeInputs {
819
+ readonly frame?: CriteriaJudgeFrame;
820
+ /** JSON text of the props the card was rendered with; bounded by {@link CRITERIA_PROPS_MAX_CHARS}. */
821
+ readonly propsJson?: string;
822
+ }
823
+ /** The judge's prompt block for the selected `judge` rows; empty when none is selected. */
824
+ declare function buildCriteriaJudgeBlock(bank: CriteriaBank, selected: CriteriaSelectionResult, inputs?: CriteriaJudgeInputs): string;
825
+
826
+ export { CARD_HEIGHT_EXPRESSION, CONTENT_HEIGHT_EXPRESSION, CRITERIA_SELECTOR_VERSION, CanvasClass, type CanvasFitPolicy, CanvasHostPresentation, CanvasJudgeRecord, CanvasPresentationOutcome, CanvasViewport, type CanvasVisualResult, type CaptureMode, type ChromiumProvider, CriteriaBank, type CriteriaCallTokens, type CriteriaContextInput, type CriteriaContextSources, type CriteriaMeasurements, type CriteriaSelectionResult, type DecodedImage, EvalIssue, type EvaluateScoreInput, EvaluationConfig, EvaluationContext, EvaluationIssue, type EvaluationLoopOptions, type EvaluationLoopResult, EvaluationResult, HOST_COLOUR_PATTERN, HOST_FRAME_BOUNDS, INK_TOLERANCE, INSTRUMENT_BY_ID, type InkExtent, type InkUnreadable, JUDGE_GROUND_MARGIN_PX, JUDGE_INK_INSET_PX, type JudgeDesignIdentity, type NaturalCaptureOptions, type PixelRegion, QualityMetadata, type ScreenshotAttempt, type ScreenshotBrowser, type ScreenshotClip, type ScreenshotDeps, type ScreenshotLauncher, type ScreenshotPage, type SdkMessage, type StoredCaptureInput, type StoredCaptureOutcome, type StoredCaptureVerdict, VISUAL_EVAL_PROMPT, VISUAL_JUDGE_MAX_OUTPUT_TOKENS, VISUAL_JUDGE_PROMPT_DIGEST, VISUAL_JUDGE_PROMPT_VERSION, type VisualEvalConfig, type VisualEvalContext, type VisualEvalDeps, type VisualEvalDetailed, type VisualEvalOutcome, VisualEvalSummary, type VisualEvaluationResult, buildCriteriaJudgeBlock, buildFixPrompt, callMultimodalLLM, canonicalCriteriaContext, canvasBlankIssue, canvasFitPolicy, canvasOverflowIssue, captureScreenshot, captureScreenshotDetailed, chromaOfCssTokens, computeEvaluationScore, createEvaluationToolsServer, criteriaContextFor, criteriaSetIdFor, cssTokensForAppTheme, decodePng, designTreeSha256, extractCompiledCode, extractCompiledCodeFromMessage, extractEvalResult, extractSourceCode, extractSourceCodeFromMessage, extractToolResultTexts, getEvaluatorSystemPrompt, judgeDesignIdentity, judgeStoredCapture, readInkExtent, resetJudgeDesignIdentityCache, resolveCriteriaBlock, resolveDesignPackageDir, resolveLaunchOptions, runEvaluation, runEvaluationLoop, runVisualEval, runVisualEvaluation, runVisualEvaluationDetailed, selectCriteria, summarizeVisualResult };