@ggui-ai/ui-gen 0.23.0 → 0.24.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/adapter-Du7P_5Fx.d.ts +201 -0
- package/dist/adapters/generation-dispatch.d.ts +33 -12
- package/dist/adapters/generation-dispatch.js +510 -128
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +5 -3
- package/dist/advanced/index.js +551 -142
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +153 -59
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +2 -1
- package/dist/check/index.js +47 -1
- package/dist/check/index.js.map +1 -1
- package/dist/{create-ui-generator-D0kbWwln.d.ts → create-ui-generator-GIhzx08x.d.ts} +34 -10
- package/dist/{dispatch-wxaIMwZt.d.ts → dispatch-BnAH56p4.d.ts} +1 -1
- package/dist/evaluation/axis-checks/index.d.ts +4 -3
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +2 -1
- package/dist/evaluation/index.d.ts +4 -3
- package/dist/evaluation/index.js.map +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +29 -10
- package/dist/harness/check/runtime-render/index.js +203 -60
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.d.ts +8 -1
- package/dist/harness/check/runtime-render/render-check-worker.js +72 -32
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.d.ts +2 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +2 -1
- package/dist/harness/runtime.d.ts +2 -1
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +11 -2
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +2 -1
- package/dist/index.d.ts +38 -3
- package/dist/index.js +553 -143
- package/dist/index.js.map +1 -1
- package/dist/patch.d.ts +2 -1
- package/dist/policy.d.ts +7 -4
- package/dist/policy.js.map +1 -1
- package/dist/tools/render-check-worker.d.ts +7 -1
- package/dist/tools/render-check-worker.js +55 -23
- package/dist/tools/render-check-worker.js.map +1 -1
- package/dist/{types-public-Ow-tNtFE.d.ts → types-public-Bk6d1WLN.d.ts} +77 -11
- package/dist/workflows.d.ts +2 -1
- package/package.json +12 -12
- package/src/adapters/generation-dispatch.ts +137 -96
- package/src/check/run-tier0.ts +80 -1
- package/src/create-ui-generator.ts +185 -95
- package/src/evaluation/types-public.ts +73 -11
- package/src/harness/check/runtime-render/adapter.ts +221 -75
- package/src/harness/check/runtime-render/index.ts +75 -2
- package/src/harness/check/runtime-render/render-check-host.ts +82 -19
- package/src/harness/check/runtime-render/render-check-worker.ts +83 -29
- package/src/harness/check/runtime-render/render-check.ts +154 -117
- package/src/harness/coding/generate-task-runner.ts +57 -4
- package/src/harness/coding/init-session.ts +13 -0
- package/src/harness/coding/run-eval-round.ts +238 -15
- package/src/harness/policy.ts +11 -0
- package/src/harness/primitive-slice.ts +104 -0
- package/src/harness/types-public.ts +9 -1
- package/src/index.ts +4 -0
- package/src/policy.ts +7 -4
- package/src/tools/render-check-worker.ts +74 -23
- package/dist/render-check-Blwj8gB6.d.ts +0 -105
package/src/policy.ts
CHANGED
|
@@ -86,12 +86,15 @@ export interface ContextPolicy {
|
|
|
86
86
|
* Axis-keyed primitives doc slice. When `"axis-keyed"`, the first-turn
|
|
87
87
|
* system prompt injects only the allowlisted primitives derived from
|
|
88
88
|
* the classification, shrinking the ~130 KB monolith to ~30–50 KB.
|
|
89
|
-
*
|
|
89
|
+
* `"axis-keyed+contract"` adds the input primitives the contract's own
|
|
90
|
+
* fields imply (ggui#1324: the axis slice alone dropped `Input` /
|
|
91
|
+
* `TextArea` from a card that edits a string). Default `"full"`.
|
|
90
92
|
*/
|
|
91
|
-
readonly primitiveDocSlice?: "full" | "axis-keyed";
|
|
93
|
+
readonly primitiveDocSlice?: "full" | "axis-keyed" | "axis-keyed+contract";
|
|
92
94
|
/**
|
|
93
|
-
* Primitives to exclude from the axis-keyed slice
|
|
94
|
-
*
|
|
95
|
+
* Primitives to exclude from the axis-keyed slice (applied after the
|
|
96
|
+
* contract additions under `"axis-keyed+contract"`). Only meaningful
|
|
97
|
+
* when `primitiveDocSlice` is one of the two slice modes.
|
|
95
98
|
*/
|
|
96
99
|
readonly primitiveDocExcludes?: readonly string[];
|
|
97
100
|
/**
|
|
@@ -27,8 +27,19 @@
|
|
|
27
27
|
* mechanical compile+vm pipeline is the shared
|
|
28
28
|
* `evaluateComponentSource` helper (also used by the in-loop probe's
|
|
29
29
|
* `loadComponent`); only the resolution policy lives here.
|
|
30
|
+
*
|
|
31
|
+
* Shutdown (ggui#1380): the compile runs on esbuild's service, a child
|
|
32
|
+
* process esbuild keeps alive for the life of this worker. After the
|
|
33
|
+
* verdict is written the worker calls `esbuild.stop()` so that child is
|
|
34
|
+
* gone before the worker is. `workerMain` is exported for the
|
|
35
|
+
* process-shape pins; `main()` runs only when this file is the process
|
|
36
|
+
* entry, so importing it never reads stdin.
|
|
30
37
|
*/
|
|
31
38
|
import { createRequire } from 'node:module';
|
|
39
|
+
import { realpathSync } from 'node:fs';
|
|
40
|
+
import { resolve as resolvePath } from 'node:path';
|
|
41
|
+
import { fileURLToPath } from 'node:url';
|
|
42
|
+
import * as esbuild from 'esbuild';
|
|
32
43
|
import type { JsonObject } from '@ggui-ai/protocol';
|
|
33
44
|
import { evaluateComponentSource } from '../internal/evaluate-component-source.js';
|
|
34
45
|
import { hostGlobals } from '../internal/open-record.js';
|
|
@@ -42,28 +53,49 @@ type WorkerOutput =
|
|
|
42
53
|
| { readonly ok: true }
|
|
43
54
|
| { readonly ok: false; readonly error: string };
|
|
44
55
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Parse one input document, render once, write the verdict. Whatever
|
|
58
|
+
* happens, esbuild's service is stopped before this returns (or
|
|
59
|
+
* rejects). If the service was never started, `stop()` is a no-op.
|
|
60
|
+
*/
|
|
61
|
+
export async function workerMain(raw: string): Promise<void> {
|
|
48
62
|
try {
|
|
49
|
-
input
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
63
|
+
let input: WorkerInput;
|
|
64
|
+
try {
|
|
65
|
+
input = JSON.parse(raw) as WorkerInput;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
emit({
|
|
68
|
+
ok: false,
|
|
69
|
+
error: `worker: malformed input JSON — ${
|
|
70
|
+
err instanceof Error ? err.message : String(err)
|
|
71
|
+
}`,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof input.sourceCode !== 'string' || input.sourceCode.length === 0) {
|
|
77
|
+
emit({ ok: false, error: 'worker: sourceCode is required' });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
59
80
|
|
|
60
|
-
|
|
61
|
-
emit(
|
|
62
|
-
|
|
81
|
+
const result = await renderOnce(input);
|
|
82
|
+
emit(result);
|
|
83
|
+
} finally {
|
|
84
|
+
// Post-verdict work must never turn a written verdict into a failure:
|
|
85
|
+
// a rejecting `stop()` would otherwise become an unhandled rejection,
|
|
86
|
+
// exit code 1, and the host discarding the verdict on stdout.
|
|
87
|
+
try {
|
|
88
|
+
await esbuild.stop();
|
|
89
|
+
} catch (err) {
|
|
90
|
+
process.stderr.write(
|
|
91
|
+
`render-check worker: esbuild.stop() failed — ${err instanceof Error ? err.message : String(err)}\n`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
63
94
|
}
|
|
95
|
+
}
|
|
64
96
|
|
|
65
|
-
|
|
66
|
-
|
|
97
|
+
async function main(): Promise<void> {
|
|
98
|
+
await workerMain(await readAllStdin());
|
|
67
99
|
}
|
|
68
100
|
|
|
69
101
|
async function renderOnce(input: WorkerInput): Promise<WorkerOutput> {
|
|
@@ -192,9 +224,28 @@ async function readAllStdin(): Promise<string> {
|
|
|
192
224
|
return buffer;
|
|
193
225
|
}
|
|
194
226
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
227
|
+
/** True when this file is the process entry (`node <this file>`), not an import. */
|
|
228
|
+
function isProcessEntry(): boolean {
|
|
229
|
+
const entry = process.argv[1];
|
|
230
|
+
if (entry === undefined) return false;
|
|
231
|
+
// Resolve BOTH sides through the filesystem: `import.meta.url` is this
|
|
232
|
+
// file's realpath while argv[1] is whatever the spawner passed — a
|
|
233
|
+
// symlinked spawn path must still read as the entry, or the worker would
|
|
234
|
+
// exit with no verdict and the host would read a silent `unverified`.
|
|
235
|
+
let entryReal: string;
|
|
236
|
+
try {
|
|
237
|
+
entryReal = realpathSync(resolvePath(entry));
|
|
238
|
+
} catch {
|
|
239
|
+
return false;
|
|
240
|
+
}
|
|
241
|
+
return entryReal === realpathSync(fileURLToPath(import.meta.url));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (isProcessEntry()) {
|
|
245
|
+
void main().catch((err: unknown) => {
|
|
246
|
+
emit({
|
|
247
|
+
ok: false,
|
|
248
|
+
error: `worker crashed: ${err instanceof Error ? err.message : String(err)}`,
|
|
249
|
+
});
|
|
199
250
|
});
|
|
200
|
-
}
|
|
251
|
+
}
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { JsonObject, DataContract } from '@ggui-ai/protocol';
|
|
2
|
-
import { P as ProbeHostLoad } from './types-public-Ow-tNtFE.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 3-state outcome. Internal to runtime-render.
|
|
6
|
-
* The adapter maps this to existing EvalIssue shapes:
|
|
7
|
-
* verified → no issue
|
|
8
|
-
* failed → fail
|
|
9
|
-
* unverified → warn
|
|
10
|
-
* skipped → no issue
|
|
11
|
-
*/
|
|
12
|
-
type CheckOutcome = "verified" | "failed" | "unverified" | "skipped";
|
|
13
|
-
interface RenderCheckIssue {
|
|
14
|
-
readonly check: "render-no-throw" | "action-wiring" | "selection-identity" | "prop-coverage" | "prop-sensitivity" | "stream-rerender" | "optional-props-omitted";
|
|
15
|
-
readonly outcome: CheckOutcome;
|
|
16
|
-
readonly subject?: string;
|
|
17
|
-
readonly reason: string;
|
|
18
|
-
/** Optional element description ("button[aria-label='Save']") for action-wiring failures. */
|
|
19
|
-
readonly elementHint?: string;
|
|
20
|
-
/**
|
|
21
|
-
* Diagnostic context from probe + AST analysis. Populated for richer feedback
|
|
22
|
-
* to the coding agent (which native props the callback flows into, what the
|
|
23
|
-
* probe observed firing, etc.).
|
|
24
|
-
*/
|
|
25
|
-
readonly diagnostics?: {
|
|
26
|
-
readonly observedJsxElements?: readonly string[];
|
|
27
|
-
readonly observedNativeProps?: readonly string[];
|
|
28
|
-
readonly observedCustomProps?: readonly string[];
|
|
29
|
-
/** For action-wiring: which actions DID fire from probe clicks (helps surface mis-wiring). */
|
|
30
|
-
readonly actionsFiredFromClicks?: readonly string[];
|
|
31
|
-
/** Surfaced to the agent: prop sourceTool hints from the contract (only if present). */
|
|
32
|
-
readonly sourceToolHints?: Readonly<Record<string, string>>;
|
|
33
|
-
/**
|
|
34
|
-
* For action-wiring (ggui#1187): what input priming did before the
|
|
35
|
-
* synthetic dispatch — how many controls it filled, or why it could not
|
|
36
|
-
* run. A "did not dispatch it" on an input-gated action reads differently
|
|
37
|
-
* beside `{ primed: 0 }` or `{ error }` than beside `{ primed: 1 }`.
|
|
38
|
-
*/
|
|
39
|
-
readonly inputPriming?: InputPrimingDiagnostic;
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Outcome of `primeInputs` before the action-wiring probe (ggui#1187). A
|
|
44
|
-
* priming failure never aborts the check — it is recorded here, on every
|
|
45
|
-
* action-wiring issue, so it is visible in the feedback instead of vanishing.
|
|
46
|
-
*/
|
|
47
|
-
type InputPrimingDiagnostic = {
|
|
48
|
-
readonly primed: number;
|
|
49
|
-
} | {
|
|
50
|
-
readonly error: string;
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* The check started but did not finish (ggui#1299). The only kind is a
|
|
54
|
-
* wall-clock timeout in the isolated worker. It is not a verdict on the
|
|
55
|
-
* component: `issues` is empty and `ok` is false because nothing was
|
|
56
|
-
* verified, never because something failed.
|
|
57
|
-
*/
|
|
58
|
-
interface RenderCheckIncomplete {
|
|
59
|
-
readonly kind: "timeout";
|
|
60
|
-
/** How long the worker ran before it was stopped. */
|
|
61
|
-
readonly elapsedMs: number;
|
|
62
|
-
/** The wall-clock bound it crossed. */
|
|
63
|
-
readonly boundMs: number;
|
|
64
|
-
}
|
|
65
|
-
interface RenderCheckResult {
|
|
66
|
-
readonly ok: boolean;
|
|
67
|
-
readonly issues: readonly RenderCheckIssue[];
|
|
68
|
-
/** Present only when the check did not finish; see {@link RenderCheckIncomplete}. */
|
|
69
|
-
readonly incomplete?: RenderCheckIncomplete;
|
|
70
|
-
readonly stats: {
|
|
71
|
-
readonly actionsChecked: number;
|
|
72
|
-
readonly streamsChecked: number;
|
|
73
|
-
readonly renderMs: number;
|
|
74
|
-
/** Host load around an isolated check (absent in-process). */
|
|
75
|
-
readonly hostLoad?: ProbeHostLoad;
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
interface RunRenderCheckInput {
|
|
79
|
-
readonly sourceCode: string;
|
|
80
|
-
readonly mockupProps: JsonObject;
|
|
81
|
-
readonly contract?: DataContract;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Run the in-loop runtime render check.
|
|
85
|
-
*
|
|
86
|
-
* Isolation dispatcher (#592): when the CALLING environment already
|
|
87
|
-
* owns a DOM (`window` + `document` on `globalThis` — e.g. a vitest
|
|
88
|
-
* `happy-dom` environment, where the environment owner installed the
|
|
89
|
-
* globals deliberately), the check runs in-process exactly as before.
|
|
90
|
-
* In a plain Node process it runs in an ISOLATED SUBPROCESS
|
|
91
|
-
* (`render-check-host.ts` → `render-check-worker.ts`), because the
|
|
92
|
-
* in-process path installs happy-dom globals on `globalThis`
|
|
93
|
-
* process-wide — a TOCTOU hazard for anything that sniffs `window`
|
|
94
|
-
* concurrently (provider SDKs throw "browser-like environment" at
|
|
95
|
-
* client construction; two overlapping checks corrupt each other's
|
|
96
|
-
* teardown). See #592 for the measured incident (4 bench cells hard-
|
|
97
|
-
* failed on the 2026-08-19 run).
|
|
98
|
-
*
|
|
99
|
-
* The host is loaded lazily so the worker bundle (which imports this
|
|
100
|
-
* module for `runRenderCheckInProcess`) never drags in the sandbox
|
|
101
|
-
* spawn machinery.
|
|
102
|
-
*/
|
|
103
|
-
declare function runRenderCheck(input: RunRenderCheckInput): Promise<RenderCheckResult>;
|
|
104
|
-
|
|
105
|
-
export { type RenderCheckIssue as R, type RenderCheckResult as a, runRenderCheck as r };
|