@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
|
@@ -10,7 +10,10 @@ import path, { dirname, resolve, join, basename } from 'path';
|
|
|
10
10
|
import { createRequire } from 'module';
|
|
11
11
|
import { Linter } from 'eslint';
|
|
12
12
|
import { createHash } from 'crypto';
|
|
13
|
+
import 'fs/promises';
|
|
13
14
|
import { tmpdir } from 'os';
|
|
15
|
+
import { Readable } from 'stream';
|
|
16
|
+
import { pipeline } from 'stream/promises';
|
|
14
17
|
import { createBrotliDecompress, createUnzip } from 'zlib';
|
|
15
18
|
import { fileURLToPath } from 'url';
|
|
16
19
|
import '@ggui-ai/sandbox';
|
|
@@ -79,6 +82,15 @@ function jsonSchemaTypeToTs(schema) {
|
|
|
79
82
|
if (schema.enum?.length) {
|
|
80
83
|
return schema.enum.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
|
|
81
84
|
}
|
|
85
|
+
if (Array.isArray(schema.type)) {
|
|
86
|
+
const { nullable: _nullable, ...rest } = schema;
|
|
87
|
+
const members = [...new Set(schema.type)].map(
|
|
88
|
+
(member) => jsonSchemaTypeToTs({ ...rest, type: member })
|
|
89
|
+
);
|
|
90
|
+
const unique = [...new Set(members)];
|
|
91
|
+
if (schema.nullable && !unique.includes("null")) unique.push("null");
|
|
92
|
+
return unique.join(" | ");
|
|
93
|
+
}
|
|
82
94
|
let result;
|
|
83
95
|
switch (schema.type) {
|
|
84
96
|
case "string":
|
|
@@ -96,7 +108,8 @@ function jsonSchemaTypeToTs(schema) {
|
|
|
96
108
|
case "array": {
|
|
97
109
|
if (schema.items) {
|
|
98
110
|
const itemType = jsonSchemaTypeToTs(schema.items);
|
|
99
|
-
|
|
111
|
+
const itemsDeclareObject = Array.isArray(schema.items.type) ? schema.items.type.includes("object") : schema.items.type === "object";
|
|
112
|
+
result = itemsDeclareObject && schema.items.properties ? `Array<${itemType}>` : itemType.includes("|") ? `(${itemType})[]` : `${itemType}[]`;
|
|
100
113
|
} else {
|
|
101
114
|
result = "unknown[]";
|
|
102
115
|
}
|
|
@@ -549,14 +562,16 @@ var OpenRouterError;
|
|
|
549
562
|
var init_types = __esm({
|
|
550
563
|
"src/adapters/openrouter/types.ts"() {
|
|
551
564
|
OpenRouterError = class extends Error {
|
|
552
|
-
constructor(message, status, code) {
|
|
565
|
+
constructor(message, status, code, headers) {
|
|
553
566
|
super(message);
|
|
554
567
|
this.status = status;
|
|
555
568
|
this.code = code;
|
|
569
|
+
this.headers = headers;
|
|
556
570
|
this.name = "OpenRouterError";
|
|
557
571
|
}
|
|
558
572
|
status;
|
|
559
573
|
code;
|
|
574
|
+
headers;
|
|
560
575
|
get isTransient() {
|
|
561
576
|
return this.status === 408 || this.status === 429 || this.status === 502 || this.status === 503;
|
|
562
577
|
}
|
|
@@ -601,7 +616,7 @@ var init_client2 = __esm({
|
|
|
601
616
|
if (!response.ok) {
|
|
602
617
|
const errorBody = await response.json().catch(() => ({ error: { message: response.statusText } }));
|
|
603
618
|
const message = errorBody.error?.message ?? response.statusText;
|
|
604
|
-
throw new OpenRouterError(message, response.status);
|
|
619
|
+
throw new OpenRouterError(message, response.status, void 0, response.headers);
|
|
605
620
|
}
|
|
606
621
|
return response.json();
|
|
607
622
|
}
|
|
@@ -619,7 +634,7 @@ var init_client2 = __esm({
|
|
|
619
634
|
if (!response.ok) {
|
|
620
635
|
const errorBody = await response.json().catch(() => ({ error: { message: response.statusText } }));
|
|
621
636
|
const message = errorBody.error?.message ?? response.statusText;
|
|
622
|
-
throw new OpenRouterError(message, response.status);
|
|
637
|
+
throw new OpenRouterError(message, response.status, void 0, response.headers);
|
|
623
638
|
}
|
|
624
639
|
if (!response.body) {
|
|
625
640
|
throw new OpenRouterError("No response body for streaming request", 500);
|
|
@@ -687,6 +702,29 @@ function errorSummary(e) {
|
|
|
687
702
|
}
|
|
688
703
|
return `${e.constructor.name}${status}${code}: ${e.message.slice(0, 120)}${body}`;
|
|
689
704
|
}
|
|
705
|
+
function isRateLimited(e) {
|
|
706
|
+
if (!(e instanceof Error) || !("status" in e)) return false;
|
|
707
|
+
return e.status === 429;
|
|
708
|
+
}
|
|
709
|
+
function extractStatus(e) {
|
|
710
|
+
if (!(e instanceof Error) || !("status" in e)) return void 0;
|
|
711
|
+
const status = e.status;
|
|
712
|
+
return typeof status === "number" ? status : void 0;
|
|
713
|
+
}
|
|
714
|
+
function extractRetryAfterSec(e) {
|
|
715
|
+
if (!(e instanceof Error) || !("headers" in e)) return void 0;
|
|
716
|
+
const headers = e.headers;
|
|
717
|
+
if (headers === null || typeof headers !== "object" || !("get" in headers) || typeof headers.get !== "function") {
|
|
718
|
+
return void 0;
|
|
719
|
+
}
|
|
720
|
+
const raw = headers.get("retry-after");
|
|
721
|
+
if (raw === null) return void 0;
|
|
722
|
+
const parsed = Number(raw);
|
|
723
|
+
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : void 0;
|
|
724
|
+
}
|
|
725
|
+
function sleep(ms) {
|
|
726
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
727
|
+
}
|
|
690
728
|
function interactionText(interaction) {
|
|
691
729
|
let text = "";
|
|
692
730
|
for (const step of interaction.steps ?? []) {
|
|
@@ -708,25 +746,41 @@ function functionCallSteps(interaction) {
|
|
|
708
746
|
function toUserInputStep(text) {
|
|
709
747
|
return { type: "user_input", content: [{ type: "text", text }] };
|
|
710
748
|
}
|
|
711
|
-
function createAgent(
|
|
749
|
+
function createAgent(providerOrConfig) {
|
|
750
|
+
const provider = typeof providerOrConfig === "string" ? providerOrConfig : providerOrConfig.provider;
|
|
751
|
+
const routeOverride = typeof providerOrConfig === "string" ? void 0 : providerOrConfig.routeOverride;
|
|
752
|
+
const onRetry = typeof providerOrConfig === "string" ? void 0 : providerOrConfig.onRetry;
|
|
712
753
|
switch (provider) {
|
|
713
754
|
case "anthropic":
|
|
714
|
-
return new AnthropicAgent();
|
|
755
|
+
return new AnthropicAgent(routeOverride, onRetry);
|
|
715
756
|
case "openai":
|
|
716
|
-
return new OpenAIAgent();
|
|
757
|
+
return new OpenAIAgent(routeOverride, onRetry);
|
|
717
758
|
case "google":
|
|
718
|
-
return new GoogleAgent();
|
|
759
|
+
return new GoogleAgent(routeOverride, onRetry);
|
|
719
760
|
case "openrouter":
|
|
720
|
-
return new OpenRouterAgent();
|
|
761
|
+
return new OpenRouterAgent(routeOverride, onRetry);
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
function createVisionAgent(config) {
|
|
765
|
+
switch (config.provider) {
|
|
766
|
+
case "anthropic":
|
|
767
|
+
return new AnthropicAgent(config.routeOverride, config.onRetry);
|
|
768
|
+
case "google":
|
|
769
|
+
return new GoogleAgent(config.routeOverride, config.onRetry);
|
|
721
770
|
}
|
|
722
771
|
}
|
|
723
|
-
var LLMAgent, AnthropicAgent, OpenAIAgent, GoogleAgent, OpenRouterAgent;
|
|
772
|
+
var MAX_RETRY_ATTEMPTS, RETRY_AFTER_CAP_SEC, DEFAULT_BACKOFF_BASE_MS, DEFAULT_BACKOFF_MAX_MS, MAX_TOTAL_RETRY_DELAY_MS, LLMAgent, AnthropicAgent, OpenAIAgent, GoogleAgent, OpenRouterAgent;
|
|
724
773
|
var init_llm_router = __esm({
|
|
725
774
|
"src/harness/llm-router.ts"() {
|
|
726
775
|
init_client();
|
|
727
776
|
init_provider_router();
|
|
728
777
|
init_tool_bridge();
|
|
729
778
|
init_llm_trace_sink();
|
|
779
|
+
MAX_RETRY_ATTEMPTS = 2;
|
|
780
|
+
RETRY_AFTER_CAP_SEC = 15;
|
|
781
|
+
DEFAULT_BACKOFF_BASE_MS = 1e3;
|
|
782
|
+
DEFAULT_BACKOFF_MAX_MS = 8e3;
|
|
783
|
+
MAX_TOTAL_RETRY_DELAY_MS = 2e4;
|
|
730
784
|
LLMAgent = class {
|
|
731
785
|
client = null;
|
|
732
786
|
// ── Session state for server-side chaining ──────────────
|
|
@@ -734,6 +788,19 @@ var init_llm_router = __esm({
|
|
|
734
788
|
// Enables turn 2+ to skip re-sending system prompt + history.
|
|
735
789
|
// Call resetSession() between independent generation runs.
|
|
736
790
|
lastSessionId;
|
|
791
|
+
/**
|
|
792
|
+
* Explicit per-call routing override — see `AgentConfig.routeOverride`.
|
|
793
|
+
* Absent when constructed via the bare `new XAgent()` form (every
|
|
794
|
+
* existing call site), so `createClient()`/`resolveModel()` fall
|
|
795
|
+
* back to `process.env` exactly as before.
|
|
796
|
+
*/
|
|
797
|
+
routeOverride;
|
|
798
|
+
/** See `AgentConfig.onRetry` (#489). Absent is a no-op. */
|
|
799
|
+
onRetry;
|
|
800
|
+
constructor(routeOverride, onRetry) {
|
|
801
|
+
this.routeOverride = routeOverride;
|
|
802
|
+
this.onRetry = onRetry;
|
|
803
|
+
}
|
|
737
804
|
async getClient() {
|
|
738
805
|
if (!this.client) {
|
|
739
806
|
this.client = await this.createClient();
|
|
@@ -767,36 +834,104 @@ var init_llm_router = __esm({
|
|
|
767
834
|
async sendToolResult(_results) {
|
|
768
835
|
}
|
|
769
836
|
/**
|
|
770
|
-
* Execute an API call
|
|
771
|
-
*
|
|
837
|
+
* Execute an API call, retrying once or twice on HTTP 429
|
|
838
|
+
* (rate-limited) before giving up (#489).
|
|
839
|
+
*
|
|
840
|
+
* Policy: on a 429, honor the provider's `Retry-After` header when
|
|
841
|
+
* present (capped at `RETRY_AFTER_CAP_SEC` — a provider asking for a
|
|
842
|
+
* longer wait is treated as "don't retry", not "wait longer": making
|
|
843
|
+
* the caller sit through 15+ more seconds on a single failed call is
|
|
844
|
+
* a bad experience regardless of what's driving the request);
|
|
845
|
+
* otherwise fall back to exponential backoff with jitter, capped at
|
|
846
|
+
* `DEFAULT_BACKOFF_MAX_MS` per attempt. Stops after
|
|
847
|
+
* `MAX_RETRY_ATTEMPTS` retries OR once the cumulative delay would
|
|
848
|
+
* exceed `MAX_TOTAL_RETRY_DELAY_MS`, whichever comes first. Any
|
|
849
|
+
* non-429 error, or a 429 with no attempts left, is logged and
|
|
850
|
+
* re-thrown immediately — unchanged from the pre-#489 behavior.
|
|
851
|
+
*
|
|
852
|
+
* **Budget scope (final-review correction):** `MAX_TOTAL_RETRY_DELAY_MS`
|
|
853
|
+
* bounds a single `apiCall()` invocation, not a whole generation. A
|
|
854
|
+
* generation issues many sequential `apiCall()` calls (coding turns,
|
|
855
|
+
* tool-result round-trips, eval rounds); under sustained throttling
|
|
856
|
+
* each one can independently add up to `MAX_TOTAL_RETRY_DELAY_MS`, so
|
|
857
|
+
* a generation with k rate-limited calls can add up to roughly `k *
|
|
858
|
+
* MAX_TOTAL_RETRY_DELAY_MS` to how long it holds its caller's
|
|
859
|
+
* resources (e.g. the caller's concurrency slot) — not a flat 20s
|
|
860
|
+
* ceiling. No shared per-generation budget is threaded here by
|
|
861
|
+
* design (accepted ruling, not an oversight): the caller's own
|
|
862
|
+
* queue/admission backstop is what bounds how long other
|
|
863
|
+
* queued work waits, independent of any one generation's retry
|
|
864
|
+
* total.
|
|
772
865
|
*/
|
|
773
866
|
async apiCall(fn) {
|
|
774
867
|
const start = Date.now();
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
868
|
+
let totalDelayMs = 0;
|
|
869
|
+
for (let attempt = 0; ; attempt++) {
|
|
870
|
+
try {
|
|
871
|
+
return await fn();
|
|
872
|
+
} catch (e) {
|
|
873
|
+
const ms = Date.now() - start;
|
|
874
|
+
if (attempt >= MAX_RETRY_ATTEMPTS || !isRateLimited(e)) {
|
|
875
|
+
console.error(`[${this.provider}] API error after ${ms}ms: ${errorSummary(e)}`);
|
|
876
|
+
throw e;
|
|
877
|
+
}
|
|
878
|
+
const retryAfterSec = extractRetryAfterSec(e);
|
|
879
|
+
if (retryAfterSec !== void 0 && retryAfterSec > RETRY_AFTER_CAP_SEC) {
|
|
880
|
+
console.error(
|
|
881
|
+
`[${this.provider}] API error after ${ms}ms (retry-after ${retryAfterSec}s exceeds ${RETRY_AFTER_CAP_SEC}s cap, not retrying): ${errorSummary(e)}`
|
|
882
|
+
);
|
|
883
|
+
throw e;
|
|
884
|
+
}
|
|
885
|
+
const delayMs = retryAfterSec !== void 0 ? retryAfterSec * 1e3 : Math.min(DEFAULT_BACKOFF_BASE_MS * 2 ** attempt, DEFAULT_BACKOFF_MAX_MS) + Math.floor(Math.random() * 250);
|
|
886
|
+
if (totalDelayMs + delayMs > MAX_TOTAL_RETRY_DELAY_MS) {
|
|
887
|
+
console.error(
|
|
888
|
+
`[${this.provider}] API error after ${ms}ms (retry budget exhausted, not retrying): ${errorSummary(e)}`
|
|
889
|
+
);
|
|
890
|
+
throw e;
|
|
891
|
+
}
|
|
892
|
+
totalDelayMs += delayMs;
|
|
893
|
+
const info = {
|
|
894
|
+
provider: this.provider,
|
|
895
|
+
attempt: attempt + 1,
|
|
896
|
+
maxAttempts: MAX_RETRY_ATTEMPTS,
|
|
897
|
+
status: extractStatus(e),
|
|
898
|
+
retryAfterSec,
|
|
899
|
+
delayMs,
|
|
900
|
+
message: errorSummary(e)
|
|
901
|
+
};
|
|
902
|
+
console.warn(
|
|
903
|
+
`[${this.provider}] rate-limited (attempt ${info.attempt}/${info.maxAttempts}), retrying in ${delayMs}ms`
|
|
904
|
+
);
|
|
905
|
+
try {
|
|
906
|
+
this.onRetry?.(info);
|
|
907
|
+
} catch (observerError) {
|
|
908
|
+
console.warn(
|
|
909
|
+
`[${this.provider}] onRetry observer threw (ignored, retry proceeds): ${errorSummary(observerError)}`
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
await sleep(delayMs);
|
|
913
|
+
}
|
|
781
914
|
}
|
|
782
915
|
}
|
|
783
916
|
};
|
|
784
917
|
AnthropicAgent = class extends LLMAgent {
|
|
785
918
|
provider = "anthropic";
|
|
786
919
|
resolveModel(model) {
|
|
787
|
-
|
|
920
|
+
const useBedrock = this.routeOverride?.useBedrock ?? process.env.CLAUDE_CODE_USE_BEDROCK === "1";
|
|
921
|
+
if (useBedrock) {
|
|
788
922
|
return getBedrockModelId(model);
|
|
789
923
|
}
|
|
790
924
|
return model.startsWith("anthropic/") ? model.slice("anthropic/".length) : model;
|
|
791
925
|
}
|
|
792
926
|
async createClient() {
|
|
793
|
-
|
|
927
|
+
const useBedrock = this.routeOverride?.useBedrock ?? process.env.CLAUDE_CODE_USE_BEDROCK === "1";
|
|
928
|
+
if (useBedrock) {
|
|
794
929
|
const { AnthropicBedrock } = await import('@anthropic-ai/bedrock-sdk');
|
|
795
930
|
return new AnthropicBedrock({
|
|
796
931
|
awsRegion: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? "us-east-1"
|
|
797
932
|
});
|
|
798
933
|
}
|
|
799
|
-
return createAnthropicClient(process.env.ANTHROPIC_API_KEY);
|
|
934
|
+
return createAnthropicClient(this.routeOverride?.apiKey ?? process.env.ANTHROPIC_API_KEY);
|
|
800
935
|
}
|
|
801
936
|
async callText(model, systemPrompt, userPrompt, maxTokens, temperature) {
|
|
802
937
|
const client = await this.getClient();
|
|
@@ -868,6 +1003,73 @@ var init_llm_router = __esm({
|
|
|
868
1003
|
throw e;
|
|
869
1004
|
}
|
|
870
1005
|
}
|
|
1006
|
+
async callVision(model, systemPrompt, userPrompt, image, maxTokens) {
|
|
1007
|
+
const client = await this.getClient();
|
|
1008
|
+
const traceId = newLlmTraceId();
|
|
1009
|
+
const startedAt = Date.now();
|
|
1010
|
+
const resolvedModel = this.resolveModel(model);
|
|
1011
|
+
const imageBlock = {
|
|
1012
|
+
type: "image",
|
|
1013
|
+
source: {
|
|
1014
|
+
type: "base64",
|
|
1015
|
+
media_type: image.mediaType,
|
|
1016
|
+
data: image.base64
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
try {
|
|
1020
|
+
const response = await this.apiCall(
|
|
1021
|
+
() => client.messages.create({
|
|
1022
|
+
model: resolvedModel,
|
|
1023
|
+
max_tokens: maxTokens ?? 1500,
|
|
1024
|
+
system: systemPrompt,
|
|
1025
|
+
messages: [
|
|
1026
|
+
{
|
|
1027
|
+
role: "user",
|
|
1028
|
+
content: [imageBlock, { type: "text", text: userPrompt }]
|
|
1029
|
+
}
|
|
1030
|
+
]
|
|
1031
|
+
})
|
|
1032
|
+
);
|
|
1033
|
+
const text = response.content.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
1034
|
+
const endedAt = Date.now();
|
|
1035
|
+
emitLlmTraceEvent({
|
|
1036
|
+
id: traceId,
|
|
1037
|
+
at: startedAt,
|
|
1038
|
+
endedAt,
|
|
1039
|
+
durationMs: endedAt - startedAt,
|
|
1040
|
+
provider: "anthropic",
|
|
1041
|
+
model: resolvedModel,
|
|
1042
|
+
kind: "callVision",
|
|
1043
|
+
systemPrompt,
|
|
1044
|
+
userPrompt,
|
|
1045
|
+
result: {
|
|
1046
|
+
inputTokens: response.usage.input_tokens,
|
|
1047
|
+
outputTokens: response.usage.output_tokens,
|
|
1048
|
+
text
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
return {
|
|
1052
|
+
text,
|
|
1053
|
+
inputTokens: response.usage.input_tokens,
|
|
1054
|
+
outputTokens: response.usage.output_tokens
|
|
1055
|
+
};
|
|
1056
|
+
} catch (e) {
|
|
1057
|
+
const endedAt = Date.now();
|
|
1058
|
+
emitLlmTraceEvent({
|
|
1059
|
+
id: traceId,
|
|
1060
|
+
at: startedAt,
|
|
1061
|
+
endedAt,
|
|
1062
|
+
durationMs: endedAt - startedAt,
|
|
1063
|
+
provider: "anthropic",
|
|
1064
|
+
model: resolvedModel,
|
|
1065
|
+
kind: "callVision",
|
|
1066
|
+
systemPrompt,
|
|
1067
|
+
userPrompt,
|
|
1068
|
+
error: { message: e instanceof Error ? e.message : String(e) }
|
|
1069
|
+
});
|
|
1070
|
+
throw e;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
871
1073
|
async callTools(model, systemPrompt, userPrompt, tools, toolChoice = "required", _scopedTools) {
|
|
872
1074
|
const client = await this.getClient();
|
|
873
1075
|
const traceId = newLlmTraceId();
|
|
@@ -1067,7 +1269,7 @@ var init_llm_router = __esm({
|
|
|
1067
1269
|
}
|
|
1068
1270
|
async createClient() {
|
|
1069
1271
|
const { default: OpenAISDK } = await import('openai');
|
|
1070
|
-
return new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY });
|
|
1272
|
+
return new OpenAISDK({ apiKey: this.routeOverride?.apiKey ?? process.env.OPENAI_API_KEY });
|
|
1071
1273
|
}
|
|
1072
1274
|
async callText(model, systemPrompt, userPrompt, maxTokens, temperature) {
|
|
1073
1275
|
const client = await this.getClient();
|
|
@@ -1217,7 +1419,7 @@ var init_llm_router = __esm({
|
|
|
1217
1419
|
async createClient() {
|
|
1218
1420
|
const { GoogleGenAI: GoogleGenAISDK } = await import('@google/genai');
|
|
1219
1421
|
return new GoogleGenAISDK({
|
|
1220
|
-
apiKey: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY,
|
|
1422
|
+
apiKey: this.routeOverride?.apiKey ?? (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY),
|
|
1221
1423
|
httpOptions: { timeout: 3e5 }
|
|
1222
1424
|
// 5 min — Pro models can be slow
|
|
1223
1425
|
});
|
|
@@ -1242,6 +1444,72 @@ var init_llm_router = __esm({
|
|
|
1242
1444
|
outputTokens: interaction.usage?.total_output_tokens ?? 0
|
|
1243
1445
|
};
|
|
1244
1446
|
}
|
|
1447
|
+
async callVision(model, systemPrompt, userPrompt, image, maxTokens) {
|
|
1448
|
+
const client = await this.getClient();
|
|
1449
|
+
const traceId = newLlmTraceId();
|
|
1450
|
+
const startedAt = Date.now();
|
|
1451
|
+
const resolvedModel = this.resolveModel(model);
|
|
1452
|
+
try {
|
|
1453
|
+
const response = await this.apiCall(
|
|
1454
|
+
() => client.models.generateContent({
|
|
1455
|
+
model: resolvedModel,
|
|
1456
|
+
contents: [
|
|
1457
|
+
{
|
|
1458
|
+
role: "user",
|
|
1459
|
+
parts: [
|
|
1460
|
+
{ inlineData: { mimeType: image.mediaType, data: image.base64 } },
|
|
1461
|
+
{ text: userPrompt }
|
|
1462
|
+
]
|
|
1463
|
+
}
|
|
1464
|
+
],
|
|
1465
|
+
config: {
|
|
1466
|
+
systemInstruction: systemPrompt,
|
|
1467
|
+
...maxTokens ? { maxOutputTokens: maxTokens } : {}
|
|
1468
|
+
}
|
|
1469
|
+
})
|
|
1470
|
+
);
|
|
1471
|
+
const text = response.candidates?.[0]?.content?.parts?.map((p) => p.text || "").join("") || "";
|
|
1472
|
+
const usage = response.usageMetadata;
|
|
1473
|
+
const result = {
|
|
1474
|
+
text,
|
|
1475
|
+
inputTokens: usage?.promptTokenCount ?? 0,
|
|
1476
|
+
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
1477
|
+
};
|
|
1478
|
+
const endedAt = Date.now();
|
|
1479
|
+
emitLlmTraceEvent({
|
|
1480
|
+
id: traceId,
|
|
1481
|
+
at: startedAt,
|
|
1482
|
+
endedAt,
|
|
1483
|
+
durationMs: endedAt - startedAt,
|
|
1484
|
+
provider: "google",
|
|
1485
|
+
model: resolvedModel,
|
|
1486
|
+
kind: "callVision",
|
|
1487
|
+
systemPrompt,
|
|
1488
|
+
userPrompt,
|
|
1489
|
+
result: {
|
|
1490
|
+
inputTokens: result.inputTokens,
|
|
1491
|
+
outputTokens: result.outputTokens,
|
|
1492
|
+
text
|
|
1493
|
+
}
|
|
1494
|
+
});
|
|
1495
|
+
return result;
|
|
1496
|
+
} catch (e) {
|
|
1497
|
+
const endedAt = Date.now();
|
|
1498
|
+
emitLlmTraceEvent({
|
|
1499
|
+
id: traceId,
|
|
1500
|
+
at: startedAt,
|
|
1501
|
+
endedAt,
|
|
1502
|
+
durationMs: endedAt - startedAt,
|
|
1503
|
+
provider: "google",
|
|
1504
|
+
model: resolvedModel,
|
|
1505
|
+
kind: "callVision",
|
|
1506
|
+
systemPrompt,
|
|
1507
|
+
userPrompt,
|
|
1508
|
+
error: { message: e instanceof Error ? e.message : String(e) }
|
|
1509
|
+
});
|
|
1510
|
+
throw e;
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1245
1513
|
async callTools(model, systemPrompt, userPrompt, tools, _toolChoice = "required", scopedTools) {
|
|
1246
1514
|
const client = await this.getClient();
|
|
1247
1515
|
const interactionTools = tools.map((t) => ({
|
|
@@ -1444,7 +1712,7 @@ var init_llm_router = __esm({
|
|
|
1444
1712
|
async createClient() {
|
|
1445
1713
|
const { OpenRouterClient: OpenRouterClient2 } = await Promise.resolve().then(() => (init_client2(), client_exports));
|
|
1446
1714
|
return new OpenRouterClient2({
|
|
1447
|
-
apiKey: process.env.OPENROUTER_API_KEY
|
|
1715
|
+
apiKey: this.routeOverride?.apiKey ?? process.env.OPENROUTER_API_KEY
|
|
1448
1716
|
});
|
|
1449
1717
|
}
|
|
1450
1718
|
async callText(model, systemPrompt, userPrompt, maxTokens, temperature) {
|
|
@@ -2239,8 +2507,8 @@ var init_ui_compiler = __esm({
|
|
|
2239
2507
|
"@ggui-ai/design/*",
|
|
2240
2508
|
"@ggui-ai/wire",
|
|
2241
2509
|
"@ggui-ai/wire/*",
|
|
2242
|
-
"@ggui-ai/react",
|
|
2243
|
-
"@ggui-ai/react/*"
|
|
2510
|
+
"@ggui-ai/mcp-apps-react",
|
|
2511
|
+
"@ggui-ai/mcp-apps-react/*"
|
|
2244
2512
|
];
|
|
2245
2513
|
MAX_BUNDLE_SIZE = 2 * 1024 * 1024;
|
|
2246
2514
|
UiValidationError = class extends Error {
|
|
@@ -4708,1414 +4976,126 @@ async function runLLMEvaluation(context, config, preWarmedContext) {
|
|
|
4708
4976
|
const model = config.model || getDefaultEvalModel(providerName);
|
|
4709
4977
|
const routerProvider = providerName === "claude" ? "anthropic" : providerName;
|
|
4710
4978
|
const motherPrompt = preWarmedContext?.motherPrompt ?? buildMotherPrompt({
|
|
4711
|
-
originalPrompt: context.originalPrompt,
|
|
4712
|
-
contract: context.contract,
|
|
4713
|
-
designSystemSummary: context.designContext
|
|
4714
|
-
});
|
|
4715
|
-
const numberedSource = context.sourceCode.split("\n").map((line, i) => `${String(i + 1).padStart(4)} | ${line}`).join("\n");
|
|
4716
|
-
const agent = createAgent(
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
const
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
const firstResult = results[0];
|
|
4737
|
-
if (firstResult && firstResult.tokens.in > 0) {
|
|
4738
|
-
cachedTokensEstimate = firstResult.tokens.in * (totalCriteriaCount - 1);
|
|
4739
|
-
}
|
|
4740
|
-
const wallMs = Date.now() - evalStart;
|
|
4741
|
-
for (const r of results) {
|
|
4742
|
-
const issueCount = r.issues.length;
|
|
4743
|
-
const status = r.pass ? "PASS" : r.tier === 1 ? "FAIL" : r.issues.some((i) => i.result === "fail") ? "FAIL" : "WARN";
|
|
4744
|
-
const issueLabel = issueCount > 0 ? ` (${issueCount} issue${issueCount > 1 ? "s" : ""})` : "";
|
|
4745
|
-
console.log(`[eval] ${r.criterion}: ${status}${issueLabel} ${(r.durationMs / 1e3).toFixed(1)}s`);
|
|
4746
|
-
}
|
|
4747
|
-
console.log(
|
|
4748
|
-
`[eval] total: ${(wallMs / 1e3).toFixed(1)}s wall (${totalCriteriaCount} parallel) | in=${totalIn} out=${totalOut} cached~=${cachedTokensEstimate} | issues=${allIssues.length} pass=${passCategories.length}`
|
|
4749
|
-
);
|
|
4750
|
-
return {
|
|
4751
|
-
issues: allIssues,
|
|
4752
|
-
pass: passCategories,
|
|
4753
|
-
inputTokens: totalIn,
|
|
4754
|
-
outputTokens: totalOut
|
|
4755
|
-
};
|
|
4756
|
-
}
|
|
4757
|
-
var TIER_1_CRITERIA, TIER_2_CRITERIA, TIER_1_CATEGORIES, TIER_2_CATEGORIES, VALID_CATEGORIES;
|
|
4758
|
-
var init_llm_evaluator = __esm({
|
|
4759
|
-
"src/evaluation/llm-evaluator.ts"() {
|
|
4760
|
-
init_llm_router();
|
|
4761
|
-
init_types_public();
|
|
4762
|
-
TIER_1_CRITERIA = ["functionality", "crash"];
|
|
4763
|
-
TIER_2_CRITERIA = ["interactivity", "accessibility", "layout", "loading", "visual"];
|
|
4764
|
-
TIER_1_CATEGORIES = /* @__PURE__ */ new Set(["functionality", "crash"]);
|
|
4765
|
-
TIER_2_CATEGORIES = /* @__PURE__ */ new Set([
|
|
4766
|
-
"interactivity",
|
|
4767
|
-
"accessibility",
|
|
4768
|
-
"layout",
|
|
4769
|
-
"loading",
|
|
4770
|
-
"visual"
|
|
4771
|
-
]);
|
|
4772
|
-
VALID_CATEGORIES = /* @__PURE__ */ new Set([
|
|
4773
|
-
...TIER_1_CATEGORIES,
|
|
4774
|
-
...TIER_2_CATEGORIES
|
|
4775
|
-
]);
|
|
4776
|
-
}
|
|
4777
|
-
});
|
|
4778
|
-
|
|
4779
|
-
// src/evaluation/cost-tracker.ts
|
|
4780
|
-
var cost_tracker_exports = {};
|
|
4781
|
-
__export(cost_tracker_exports, {
|
|
4782
|
-
CostTracker: () => CostTracker,
|
|
4783
|
-
pricePer1k: () => pricePer1k
|
|
4784
|
-
});
|
|
4785
|
-
function resolveRegistryId(model) {
|
|
4786
|
-
const keys = Object.keys(MODEL_REGISTRY);
|
|
4787
|
-
if (keys.includes(model)) return model;
|
|
4788
|
-
const bySuffix = keys.find((id) => id.endsWith(`/${model}`));
|
|
4789
|
-
if (bySuffix) return bySuffix;
|
|
4790
|
-
const undated = model.replace(/-\d{8}$/, "");
|
|
4791
|
-
return keys.find((id) => id.endsWith(`/${undated}`)) ?? null;
|
|
4792
|
-
}
|
|
4793
|
-
function pricePer1k(model) {
|
|
4794
|
-
const id = resolveRegistryId(model);
|
|
4795
|
-
if (id === null) return FALLBACK_PER_1K;
|
|
4796
|
-
const { costs } = MODEL_REGISTRY[id];
|
|
4797
|
-
return { input: costs.inputPer1M / 1e3, output: costs.outputPer1M / 1e3 };
|
|
4798
|
-
}
|
|
4799
|
-
var FALLBACK_PER_1K, CostTracker;
|
|
4800
|
-
var init_cost_tracker = __esm({
|
|
4801
|
-
"src/evaluation/cost-tracker.ts"() {
|
|
4802
|
-
FALLBACK_PER_1K = { input: 3e-3, output: 0.015 };
|
|
4803
|
-
CostTracker = class {
|
|
4804
|
-
constructor(maxBudget) {
|
|
4805
|
-
this.maxBudget = maxBudget;
|
|
4806
|
-
}
|
|
4807
|
-
maxBudget;
|
|
4808
|
-
totalCost = 0;
|
|
4809
|
-
record(model, inputTokens, outputTokens) {
|
|
4810
|
-
const prices = pricePer1k(model);
|
|
4811
|
-
const cost = inputTokens / 1e3 * prices.input + outputTokens / 1e3 * prices.output;
|
|
4812
|
-
this.totalCost += cost;
|
|
4813
|
-
return cost;
|
|
4814
|
-
}
|
|
4815
|
-
canContinue() {
|
|
4816
|
-
if (this.maxBudget === null) return true;
|
|
4817
|
-
return this.totalCost < this.maxBudget;
|
|
4818
|
-
}
|
|
4819
|
-
getTotal() {
|
|
4820
|
-
return this.totalCost;
|
|
4821
|
-
}
|
|
4822
|
-
getRemaining() {
|
|
4823
|
-
if (this.maxBudget === null) return null;
|
|
4824
|
-
return Math.max(0, this.maxBudget - this.totalCost);
|
|
4825
|
-
}
|
|
4826
|
-
};
|
|
4827
|
-
}
|
|
4828
|
-
});
|
|
4829
|
-
|
|
4830
|
-
// ../../node_modules/ms/index.js
|
|
4831
|
-
var require_ms = __commonJS({
|
|
4832
|
-
"../../node_modules/ms/index.js"(exports, module) {
|
|
4833
|
-
var s = 1e3;
|
|
4834
|
-
var m = s * 60;
|
|
4835
|
-
var h = m * 60;
|
|
4836
|
-
var d = h * 24;
|
|
4837
|
-
var w = d * 7;
|
|
4838
|
-
var y = d * 365.25;
|
|
4839
|
-
module.exports = function(val, options) {
|
|
4840
|
-
options = options || {};
|
|
4841
|
-
var type = typeof val;
|
|
4842
|
-
if (type === "string" && val.length > 0) {
|
|
4843
|
-
return parse(val);
|
|
4844
|
-
} else if (type === "number" && isFinite(val)) {
|
|
4845
|
-
return options.long ? fmtLong(val) : fmtShort(val);
|
|
4846
|
-
}
|
|
4847
|
-
throw new Error(
|
|
4848
|
-
"val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
|
|
4849
|
-
);
|
|
4850
|
-
};
|
|
4851
|
-
function parse(str) {
|
|
4852
|
-
str = String(str);
|
|
4853
|
-
if (str.length > 100) {
|
|
4854
|
-
return;
|
|
4855
|
-
}
|
|
4856
|
-
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
|
|
4857
|
-
str
|
|
4858
|
-
);
|
|
4859
|
-
if (!match) {
|
|
4860
|
-
return;
|
|
4861
|
-
}
|
|
4862
|
-
var n = parseFloat(match[1]);
|
|
4863
|
-
var type = (match[2] || "ms").toLowerCase();
|
|
4864
|
-
switch (type) {
|
|
4865
|
-
case "years":
|
|
4866
|
-
case "year":
|
|
4867
|
-
case "yrs":
|
|
4868
|
-
case "yr":
|
|
4869
|
-
case "y":
|
|
4870
|
-
return n * y;
|
|
4871
|
-
case "weeks":
|
|
4872
|
-
case "week":
|
|
4873
|
-
case "w":
|
|
4874
|
-
return n * w;
|
|
4875
|
-
case "days":
|
|
4876
|
-
case "day":
|
|
4877
|
-
case "d":
|
|
4878
|
-
return n * d;
|
|
4879
|
-
case "hours":
|
|
4880
|
-
case "hour":
|
|
4881
|
-
case "hrs":
|
|
4882
|
-
case "hr":
|
|
4883
|
-
case "h":
|
|
4884
|
-
return n * h;
|
|
4885
|
-
case "minutes":
|
|
4886
|
-
case "minute":
|
|
4887
|
-
case "mins":
|
|
4888
|
-
case "min":
|
|
4889
|
-
case "m":
|
|
4890
|
-
return n * m;
|
|
4891
|
-
case "seconds":
|
|
4892
|
-
case "second":
|
|
4893
|
-
case "secs":
|
|
4894
|
-
case "sec":
|
|
4895
|
-
case "s":
|
|
4896
|
-
return n * s;
|
|
4897
|
-
case "milliseconds":
|
|
4898
|
-
case "millisecond":
|
|
4899
|
-
case "msecs":
|
|
4900
|
-
case "msec":
|
|
4901
|
-
case "ms":
|
|
4902
|
-
return n;
|
|
4903
|
-
default:
|
|
4904
|
-
return void 0;
|
|
4905
|
-
}
|
|
4906
|
-
}
|
|
4907
|
-
function fmtShort(ms) {
|
|
4908
|
-
var msAbs = Math.abs(ms);
|
|
4909
|
-
if (msAbs >= d) {
|
|
4910
|
-
return Math.round(ms / d) + "d";
|
|
4911
|
-
}
|
|
4912
|
-
if (msAbs >= h) {
|
|
4913
|
-
return Math.round(ms / h) + "h";
|
|
4914
|
-
}
|
|
4915
|
-
if (msAbs >= m) {
|
|
4916
|
-
return Math.round(ms / m) + "m";
|
|
4917
|
-
}
|
|
4918
|
-
if (msAbs >= s) {
|
|
4919
|
-
return Math.round(ms / s) + "s";
|
|
4920
|
-
}
|
|
4921
|
-
return ms + "ms";
|
|
4922
|
-
}
|
|
4923
|
-
function fmtLong(ms) {
|
|
4924
|
-
var msAbs = Math.abs(ms);
|
|
4925
|
-
if (msAbs >= d) {
|
|
4926
|
-
return plural(ms, msAbs, d, "day");
|
|
4927
|
-
}
|
|
4928
|
-
if (msAbs >= h) {
|
|
4929
|
-
return plural(ms, msAbs, h, "hour");
|
|
4930
|
-
}
|
|
4931
|
-
if (msAbs >= m) {
|
|
4932
|
-
return plural(ms, msAbs, m, "minute");
|
|
4933
|
-
}
|
|
4934
|
-
if (msAbs >= s) {
|
|
4935
|
-
return plural(ms, msAbs, s, "second");
|
|
4936
|
-
}
|
|
4937
|
-
return ms + " ms";
|
|
4938
|
-
}
|
|
4939
|
-
function plural(ms, msAbs, n, name) {
|
|
4940
|
-
var isPlural = msAbs >= n * 1.5;
|
|
4941
|
-
return Math.round(ms / n) + " " + name + (isPlural ? "s" : "");
|
|
4942
|
-
}
|
|
4943
|
-
}
|
|
4944
|
-
});
|
|
4945
|
-
|
|
4946
|
-
// ../../node_modules/debug/src/common.js
|
|
4947
|
-
var require_common = __commonJS({
|
|
4948
|
-
"../../node_modules/debug/src/common.js"(exports, module) {
|
|
4949
|
-
function setup(env) {
|
|
4950
|
-
createDebug.debug = createDebug;
|
|
4951
|
-
createDebug.default = createDebug;
|
|
4952
|
-
createDebug.coerce = coerce;
|
|
4953
|
-
createDebug.disable = disable;
|
|
4954
|
-
createDebug.enable = enable;
|
|
4955
|
-
createDebug.enabled = enabled;
|
|
4956
|
-
createDebug.humanize = require_ms();
|
|
4957
|
-
createDebug.destroy = destroy;
|
|
4958
|
-
Object.keys(env).forEach((key) => {
|
|
4959
|
-
createDebug[key] = env[key];
|
|
4960
|
-
});
|
|
4961
|
-
createDebug.names = [];
|
|
4962
|
-
createDebug.skips = [];
|
|
4963
|
-
createDebug.formatters = {};
|
|
4964
|
-
function selectColor(namespace) {
|
|
4965
|
-
let hash = 0;
|
|
4966
|
-
for (let i = 0; i < namespace.length; i++) {
|
|
4967
|
-
hash = (hash << 5) - hash + namespace.charCodeAt(i);
|
|
4968
|
-
hash |= 0;
|
|
4969
|
-
}
|
|
4970
|
-
return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
|
|
4971
|
-
}
|
|
4972
|
-
createDebug.selectColor = selectColor;
|
|
4973
|
-
function createDebug(namespace) {
|
|
4974
|
-
let prevTime;
|
|
4975
|
-
let enableOverride = null;
|
|
4976
|
-
let namespacesCache;
|
|
4977
|
-
let enabledCache;
|
|
4978
|
-
function debug(...args) {
|
|
4979
|
-
if (!debug.enabled) {
|
|
4980
|
-
return;
|
|
4981
|
-
}
|
|
4982
|
-
const self = debug;
|
|
4983
|
-
const curr = Number(/* @__PURE__ */ new Date());
|
|
4984
|
-
const ms = curr - (prevTime || curr);
|
|
4985
|
-
self.diff = ms;
|
|
4986
|
-
self.prev = prevTime;
|
|
4987
|
-
self.curr = curr;
|
|
4988
|
-
prevTime = curr;
|
|
4989
|
-
args[0] = createDebug.coerce(args[0]);
|
|
4990
|
-
if (typeof args[0] !== "string") {
|
|
4991
|
-
args.unshift("%O");
|
|
4992
|
-
}
|
|
4993
|
-
let index = 0;
|
|
4994
|
-
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
|
|
4995
|
-
if (match === "%%") {
|
|
4996
|
-
return "%";
|
|
4997
|
-
}
|
|
4998
|
-
index++;
|
|
4999
|
-
const formatter = createDebug.formatters[format];
|
|
5000
|
-
if (typeof formatter === "function") {
|
|
5001
|
-
const val = args[index];
|
|
5002
|
-
match = formatter.call(self, val);
|
|
5003
|
-
args.splice(index, 1);
|
|
5004
|
-
index--;
|
|
5005
|
-
}
|
|
5006
|
-
return match;
|
|
5007
|
-
});
|
|
5008
|
-
createDebug.formatArgs.call(self, args);
|
|
5009
|
-
const logFn = self.log || createDebug.log;
|
|
5010
|
-
logFn.apply(self, args);
|
|
5011
|
-
}
|
|
5012
|
-
debug.namespace = namespace;
|
|
5013
|
-
debug.useColors = createDebug.useColors();
|
|
5014
|
-
debug.color = createDebug.selectColor(namespace);
|
|
5015
|
-
debug.extend = extend;
|
|
5016
|
-
debug.destroy = createDebug.destroy;
|
|
5017
|
-
Object.defineProperty(debug, "enabled", {
|
|
5018
|
-
enumerable: true,
|
|
5019
|
-
configurable: false,
|
|
5020
|
-
get: () => {
|
|
5021
|
-
if (enableOverride !== null) {
|
|
5022
|
-
return enableOverride;
|
|
5023
|
-
}
|
|
5024
|
-
if (namespacesCache !== createDebug.namespaces) {
|
|
5025
|
-
namespacesCache = createDebug.namespaces;
|
|
5026
|
-
enabledCache = createDebug.enabled(namespace);
|
|
5027
|
-
}
|
|
5028
|
-
return enabledCache;
|
|
5029
|
-
},
|
|
5030
|
-
set: (v) => {
|
|
5031
|
-
enableOverride = v;
|
|
5032
|
-
}
|
|
5033
|
-
});
|
|
5034
|
-
if (typeof createDebug.init === "function") {
|
|
5035
|
-
createDebug.init(debug);
|
|
5036
|
-
}
|
|
5037
|
-
return debug;
|
|
5038
|
-
}
|
|
5039
|
-
function extend(namespace, delimiter) {
|
|
5040
|
-
const newDebug = createDebug(this.namespace + (typeof delimiter === "undefined" ? ":" : delimiter) + namespace);
|
|
5041
|
-
newDebug.log = this.log;
|
|
5042
|
-
return newDebug;
|
|
5043
|
-
}
|
|
5044
|
-
function enable(namespaces) {
|
|
5045
|
-
createDebug.save(namespaces);
|
|
5046
|
-
createDebug.namespaces = namespaces;
|
|
5047
|
-
createDebug.names = [];
|
|
5048
|
-
createDebug.skips = [];
|
|
5049
|
-
const split = (typeof namespaces === "string" ? namespaces : "").trim().replace(/\s+/g, ",").split(",").filter(Boolean);
|
|
5050
|
-
for (const ns of split) {
|
|
5051
|
-
if (ns[0] === "-") {
|
|
5052
|
-
createDebug.skips.push(ns.slice(1));
|
|
5053
|
-
} else {
|
|
5054
|
-
createDebug.names.push(ns);
|
|
5055
|
-
}
|
|
5056
|
-
}
|
|
5057
|
-
}
|
|
5058
|
-
function matchesTemplate(search, template) {
|
|
5059
|
-
let searchIndex = 0;
|
|
5060
|
-
let templateIndex = 0;
|
|
5061
|
-
let starIndex = -1;
|
|
5062
|
-
let matchIndex = 0;
|
|
5063
|
-
while (searchIndex < search.length) {
|
|
5064
|
-
if (templateIndex < template.length && (template[templateIndex] === search[searchIndex] || template[templateIndex] === "*")) {
|
|
5065
|
-
if (template[templateIndex] === "*") {
|
|
5066
|
-
starIndex = templateIndex;
|
|
5067
|
-
matchIndex = searchIndex;
|
|
5068
|
-
templateIndex++;
|
|
5069
|
-
} else {
|
|
5070
|
-
searchIndex++;
|
|
5071
|
-
templateIndex++;
|
|
5072
|
-
}
|
|
5073
|
-
} else if (starIndex !== -1) {
|
|
5074
|
-
templateIndex = starIndex + 1;
|
|
5075
|
-
matchIndex++;
|
|
5076
|
-
searchIndex = matchIndex;
|
|
5077
|
-
} else {
|
|
5078
|
-
return false;
|
|
5079
|
-
}
|
|
5080
|
-
}
|
|
5081
|
-
while (templateIndex < template.length && template[templateIndex] === "*") {
|
|
5082
|
-
templateIndex++;
|
|
5083
|
-
}
|
|
5084
|
-
return templateIndex === template.length;
|
|
5085
|
-
}
|
|
5086
|
-
function disable() {
|
|
5087
|
-
const namespaces = [
|
|
5088
|
-
...createDebug.names,
|
|
5089
|
-
...createDebug.skips.map((namespace) => "-" + namespace)
|
|
5090
|
-
].join(",");
|
|
5091
|
-
createDebug.enable("");
|
|
5092
|
-
return namespaces;
|
|
5093
|
-
}
|
|
5094
|
-
function enabled(name) {
|
|
5095
|
-
for (const skip of createDebug.skips) {
|
|
5096
|
-
if (matchesTemplate(name, skip)) {
|
|
5097
|
-
return false;
|
|
5098
|
-
}
|
|
5099
|
-
}
|
|
5100
|
-
for (const ns of createDebug.names) {
|
|
5101
|
-
if (matchesTemplate(name, ns)) {
|
|
5102
|
-
return true;
|
|
5103
|
-
}
|
|
5104
|
-
}
|
|
5105
|
-
return false;
|
|
5106
|
-
}
|
|
5107
|
-
function coerce(val) {
|
|
5108
|
-
if (val instanceof Error) {
|
|
5109
|
-
return val.stack || val.message;
|
|
5110
|
-
}
|
|
5111
|
-
return val;
|
|
5112
|
-
}
|
|
5113
|
-
function destroy() {
|
|
5114
|
-
console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
5115
|
-
}
|
|
5116
|
-
createDebug.enable(createDebug.load());
|
|
5117
|
-
return createDebug;
|
|
5118
|
-
}
|
|
5119
|
-
module.exports = setup;
|
|
5120
|
-
}
|
|
5121
|
-
});
|
|
5122
|
-
|
|
5123
|
-
// ../../node_modules/debug/src/browser.js
|
|
5124
|
-
var require_browser = __commonJS({
|
|
5125
|
-
"../../node_modules/debug/src/browser.js"(exports, module) {
|
|
5126
|
-
exports.formatArgs = formatArgs;
|
|
5127
|
-
exports.save = save;
|
|
5128
|
-
exports.load = load;
|
|
5129
|
-
exports.useColors = useColors;
|
|
5130
|
-
exports.storage = localstorage();
|
|
5131
|
-
exports.destroy = /* @__PURE__ */ (() => {
|
|
5132
|
-
let warned = false;
|
|
5133
|
-
return () => {
|
|
5134
|
-
if (!warned) {
|
|
5135
|
-
warned = true;
|
|
5136
|
-
console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
5137
|
-
}
|
|
5138
|
-
};
|
|
5139
|
-
})();
|
|
5140
|
-
exports.colors = [
|
|
5141
|
-
"#0000CC",
|
|
5142
|
-
"#0000FF",
|
|
5143
|
-
"#0033CC",
|
|
5144
|
-
"#0033FF",
|
|
5145
|
-
"#0066CC",
|
|
5146
|
-
"#0066FF",
|
|
5147
|
-
"#0099CC",
|
|
5148
|
-
"#0099FF",
|
|
5149
|
-
"#00CC00",
|
|
5150
|
-
"#00CC33",
|
|
5151
|
-
"#00CC66",
|
|
5152
|
-
"#00CC99",
|
|
5153
|
-
"#00CCCC",
|
|
5154
|
-
"#00CCFF",
|
|
5155
|
-
"#3300CC",
|
|
5156
|
-
"#3300FF",
|
|
5157
|
-
"#3333CC",
|
|
5158
|
-
"#3333FF",
|
|
5159
|
-
"#3366CC",
|
|
5160
|
-
"#3366FF",
|
|
5161
|
-
"#3399CC",
|
|
5162
|
-
"#3399FF",
|
|
5163
|
-
"#33CC00",
|
|
5164
|
-
"#33CC33",
|
|
5165
|
-
"#33CC66",
|
|
5166
|
-
"#33CC99",
|
|
5167
|
-
"#33CCCC",
|
|
5168
|
-
"#33CCFF",
|
|
5169
|
-
"#6600CC",
|
|
5170
|
-
"#6600FF",
|
|
5171
|
-
"#6633CC",
|
|
5172
|
-
"#6633FF",
|
|
5173
|
-
"#66CC00",
|
|
5174
|
-
"#66CC33",
|
|
5175
|
-
"#9900CC",
|
|
5176
|
-
"#9900FF",
|
|
5177
|
-
"#9933CC",
|
|
5178
|
-
"#9933FF",
|
|
5179
|
-
"#99CC00",
|
|
5180
|
-
"#99CC33",
|
|
5181
|
-
"#CC0000",
|
|
5182
|
-
"#CC0033",
|
|
5183
|
-
"#CC0066",
|
|
5184
|
-
"#CC0099",
|
|
5185
|
-
"#CC00CC",
|
|
5186
|
-
"#CC00FF",
|
|
5187
|
-
"#CC3300",
|
|
5188
|
-
"#CC3333",
|
|
5189
|
-
"#CC3366",
|
|
5190
|
-
"#CC3399",
|
|
5191
|
-
"#CC33CC",
|
|
5192
|
-
"#CC33FF",
|
|
5193
|
-
"#CC6600",
|
|
5194
|
-
"#CC6633",
|
|
5195
|
-
"#CC9900",
|
|
5196
|
-
"#CC9933",
|
|
5197
|
-
"#CCCC00",
|
|
5198
|
-
"#CCCC33",
|
|
5199
|
-
"#FF0000",
|
|
5200
|
-
"#FF0033",
|
|
5201
|
-
"#FF0066",
|
|
5202
|
-
"#FF0099",
|
|
5203
|
-
"#FF00CC",
|
|
5204
|
-
"#FF00FF",
|
|
5205
|
-
"#FF3300",
|
|
5206
|
-
"#FF3333",
|
|
5207
|
-
"#FF3366",
|
|
5208
|
-
"#FF3399",
|
|
5209
|
-
"#FF33CC",
|
|
5210
|
-
"#FF33FF",
|
|
5211
|
-
"#FF6600",
|
|
5212
|
-
"#FF6633",
|
|
5213
|
-
"#FF9900",
|
|
5214
|
-
"#FF9933",
|
|
5215
|
-
"#FFCC00",
|
|
5216
|
-
"#FFCC33"
|
|
5217
|
-
];
|
|
5218
|
-
function useColors() {
|
|
5219
|
-
if (typeof window !== "undefined" && window.process && (window.process.type === "renderer" || window.process.__nwjs)) {
|
|
5220
|
-
return true;
|
|
5221
|
-
}
|
|
5222
|
-
if (typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
|
|
5223
|
-
return false;
|
|
5224
|
-
}
|
|
5225
|
-
let m;
|
|
5226
|
-
return typeof document !== "undefined" && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773
|
|
5227
|
-
typeof window !== "undefined" && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31?
|
|
5228
|
-
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
|
5229
|
-
typeof navigator !== "undefined" && navigator.userAgent && (m = navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)) && parseInt(m[1], 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker
|
|
5230
|
-
typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/);
|
|
5231
|
-
}
|
|
5232
|
-
function formatArgs(args) {
|
|
5233
|
-
args[0] = (this.useColors ? "%c" : "") + this.namespace + (this.useColors ? " %c" : " ") + args[0] + (this.useColors ? "%c " : " ") + "+" + module.exports.humanize(this.diff);
|
|
5234
|
-
if (!this.useColors) {
|
|
5235
|
-
return;
|
|
5236
|
-
}
|
|
5237
|
-
const c = "color: " + this.color;
|
|
5238
|
-
args.splice(1, 0, c, "color: inherit");
|
|
5239
|
-
let index = 0;
|
|
5240
|
-
let lastC = 0;
|
|
5241
|
-
args[0].replace(/%[a-zA-Z%]/g, (match) => {
|
|
5242
|
-
if (match === "%%") {
|
|
5243
|
-
return;
|
|
5244
|
-
}
|
|
5245
|
-
index++;
|
|
5246
|
-
if (match === "%c") {
|
|
5247
|
-
lastC = index;
|
|
5248
|
-
}
|
|
5249
|
-
});
|
|
5250
|
-
args.splice(lastC, 0, c);
|
|
5251
|
-
}
|
|
5252
|
-
exports.log = console.debug || console.log || (() => {
|
|
5253
|
-
});
|
|
5254
|
-
function save(namespaces) {
|
|
5255
|
-
try {
|
|
5256
|
-
if (namespaces) {
|
|
5257
|
-
exports.storage.setItem("debug", namespaces);
|
|
5258
|
-
} else {
|
|
5259
|
-
exports.storage.removeItem("debug");
|
|
5260
|
-
}
|
|
5261
|
-
} catch (error) {
|
|
5262
|
-
}
|
|
5263
|
-
}
|
|
5264
|
-
function load() {
|
|
5265
|
-
let r;
|
|
5266
|
-
try {
|
|
5267
|
-
r = exports.storage.getItem("debug") || exports.storage.getItem("DEBUG");
|
|
5268
|
-
} catch (error) {
|
|
5269
|
-
}
|
|
5270
|
-
if (!r && typeof process !== "undefined" && "env" in process) {
|
|
5271
|
-
r = process.env.DEBUG;
|
|
5272
|
-
}
|
|
5273
|
-
return r;
|
|
5274
|
-
}
|
|
5275
|
-
function localstorage() {
|
|
5276
|
-
try {
|
|
5277
|
-
return localStorage;
|
|
5278
|
-
} catch (error) {
|
|
5279
|
-
}
|
|
5280
|
-
}
|
|
5281
|
-
module.exports = require_common()(exports);
|
|
5282
|
-
var { formatters } = module.exports;
|
|
5283
|
-
formatters.j = function(v) {
|
|
5284
|
-
try {
|
|
5285
|
-
return JSON.stringify(v);
|
|
5286
|
-
} catch (error) {
|
|
5287
|
-
return "[UnexpectedJSONParseError]: " + error.message;
|
|
5288
|
-
}
|
|
5289
|
-
};
|
|
5290
|
-
}
|
|
5291
|
-
});
|
|
5292
|
-
|
|
5293
|
-
// ../../node_modules/has-flag/index.js
|
|
5294
|
-
var require_has_flag = __commonJS({
|
|
5295
|
-
"../../node_modules/has-flag/index.js"(exports, module) {
|
|
5296
|
-
module.exports = (flag, argv = process.argv) => {
|
|
5297
|
-
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
5298
|
-
const position = argv.indexOf(prefix + flag);
|
|
5299
|
-
const terminatorPosition = argv.indexOf("--");
|
|
5300
|
-
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
5301
|
-
};
|
|
5302
|
-
}
|
|
5303
|
-
});
|
|
5304
|
-
|
|
5305
|
-
// ../../node_modules/supports-color/index.js
|
|
5306
|
-
var require_supports_color = __commonJS({
|
|
5307
|
-
"../../node_modules/supports-color/index.js"(exports, module) {
|
|
5308
|
-
var os = __require("os");
|
|
5309
|
-
var tty = __require("tty");
|
|
5310
|
-
var hasFlag = require_has_flag();
|
|
5311
|
-
var { env } = process;
|
|
5312
|
-
var forceColor;
|
|
5313
|
-
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
5314
|
-
forceColor = 0;
|
|
5315
|
-
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
5316
|
-
forceColor = 1;
|
|
5317
|
-
}
|
|
5318
|
-
if ("FORCE_COLOR" in env) {
|
|
5319
|
-
if (env.FORCE_COLOR === "true") {
|
|
5320
|
-
forceColor = 1;
|
|
5321
|
-
} else if (env.FORCE_COLOR === "false") {
|
|
5322
|
-
forceColor = 0;
|
|
5323
|
-
} else {
|
|
5324
|
-
forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
|
|
5325
|
-
}
|
|
5326
|
-
}
|
|
5327
|
-
function translateLevel(level) {
|
|
5328
|
-
if (level === 0) {
|
|
5329
|
-
return false;
|
|
5330
|
-
}
|
|
5331
|
-
return {
|
|
5332
|
-
level,
|
|
5333
|
-
hasBasic: true,
|
|
5334
|
-
has256: level >= 2,
|
|
5335
|
-
has16m: level >= 3
|
|
5336
|
-
};
|
|
5337
|
-
}
|
|
5338
|
-
function supportsColor(haveStream, streamIsTTY) {
|
|
5339
|
-
if (forceColor === 0) {
|
|
5340
|
-
return 0;
|
|
5341
|
-
}
|
|
5342
|
-
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
5343
|
-
return 3;
|
|
5344
|
-
}
|
|
5345
|
-
if (hasFlag("color=256")) {
|
|
5346
|
-
return 2;
|
|
5347
|
-
}
|
|
5348
|
-
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
5349
|
-
return 0;
|
|
5350
|
-
}
|
|
5351
|
-
const min = forceColor || 0;
|
|
5352
|
-
if (env.TERM === "dumb") {
|
|
5353
|
-
return min;
|
|
5354
|
-
}
|
|
5355
|
-
if (process.platform === "win32") {
|
|
5356
|
-
const osRelease = os.release().split(".");
|
|
5357
|
-
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
5358
|
-
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
5359
|
-
}
|
|
5360
|
-
return 1;
|
|
5361
|
-
}
|
|
5362
|
-
if ("CI" in env) {
|
|
5363
|
-
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign) => sign in env) || env.CI_NAME === "codeship") {
|
|
5364
|
-
return 1;
|
|
5365
|
-
}
|
|
5366
|
-
return min;
|
|
5367
|
-
}
|
|
5368
|
-
if ("TEAMCITY_VERSION" in env) {
|
|
5369
|
-
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
5370
|
-
}
|
|
5371
|
-
if (env.COLORTERM === "truecolor") {
|
|
5372
|
-
return 3;
|
|
5373
|
-
}
|
|
5374
|
-
if ("TERM_PROGRAM" in env) {
|
|
5375
|
-
const version = parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
5376
|
-
switch (env.TERM_PROGRAM) {
|
|
5377
|
-
case "iTerm.app":
|
|
5378
|
-
return version >= 3 ? 3 : 2;
|
|
5379
|
-
case "Apple_Terminal":
|
|
5380
|
-
return 2;
|
|
5381
|
-
}
|
|
5382
|
-
}
|
|
5383
|
-
if (/-256(color)?$/i.test(env.TERM)) {
|
|
5384
|
-
return 2;
|
|
5385
|
-
}
|
|
5386
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
5387
|
-
return 1;
|
|
5388
|
-
}
|
|
5389
|
-
if ("COLORTERM" in env) {
|
|
5390
|
-
return 1;
|
|
5391
|
-
}
|
|
5392
|
-
return min;
|
|
5393
|
-
}
|
|
5394
|
-
function getSupportLevel(stream) {
|
|
5395
|
-
const level = supportsColor(stream, stream && stream.isTTY);
|
|
5396
|
-
return translateLevel(level);
|
|
5397
|
-
}
|
|
5398
|
-
module.exports = {
|
|
5399
|
-
supportsColor: getSupportLevel,
|
|
5400
|
-
stdout: translateLevel(supportsColor(true, tty.isatty(1))),
|
|
5401
|
-
stderr: translateLevel(supportsColor(true, tty.isatty(2)))
|
|
5402
|
-
};
|
|
5403
|
-
}
|
|
5404
|
-
});
|
|
5405
|
-
|
|
5406
|
-
// ../../node_modules/debug/src/node.js
|
|
5407
|
-
var require_node = __commonJS({
|
|
5408
|
-
"../../node_modules/debug/src/node.js"(exports, module) {
|
|
5409
|
-
var tty = __require("tty");
|
|
5410
|
-
var util = __require("util");
|
|
5411
|
-
exports.init = init;
|
|
5412
|
-
exports.log = log;
|
|
5413
|
-
exports.formatArgs = formatArgs;
|
|
5414
|
-
exports.save = save;
|
|
5415
|
-
exports.load = load;
|
|
5416
|
-
exports.useColors = useColors;
|
|
5417
|
-
exports.destroy = util.deprecate(
|
|
5418
|
-
() => {
|
|
5419
|
-
},
|
|
5420
|
-
"Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."
|
|
5421
|
-
);
|
|
5422
|
-
exports.colors = [6, 2, 3, 4, 5, 1];
|
|
5423
|
-
try {
|
|
5424
|
-
const supportsColor = require_supports_color();
|
|
5425
|
-
if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
|
|
5426
|
-
exports.colors = [
|
|
5427
|
-
20,
|
|
5428
|
-
21,
|
|
5429
|
-
26,
|
|
5430
|
-
27,
|
|
5431
|
-
32,
|
|
5432
|
-
33,
|
|
5433
|
-
38,
|
|
5434
|
-
39,
|
|
5435
|
-
40,
|
|
5436
|
-
41,
|
|
5437
|
-
42,
|
|
5438
|
-
43,
|
|
5439
|
-
44,
|
|
5440
|
-
45,
|
|
5441
|
-
56,
|
|
5442
|
-
57,
|
|
5443
|
-
62,
|
|
5444
|
-
63,
|
|
5445
|
-
68,
|
|
5446
|
-
69,
|
|
5447
|
-
74,
|
|
5448
|
-
75,
|
|
5449
|
-
76,
|
|
5450
|
-
77,
|
|
5451
|
-
78,
|
|
5452
|
-
79,
|
|
5453
|
-
80,
|
|
5454
|
-
81,
|
|
5455
|
-
92,
|
|
5456
|
-
93,
|
|
5457
|
-
98,
|
|
5458
|
-
99,
|
|
5459
|
-
112,
|
|
5460
|
-
113,
|
|
5461
|
-
128,
|
|
5462
|
-
129,
|
|
5463
|
-
134,
|
|
5464
|
-
135,
|
|
5465
|
-
148,
|
|
5466
|
-
149,
|
|
5467
|
-
160,
|
|
5468
|
-
161,
|
|
5469
|
-
162,
|
|
5470
|
-
163,
|
|
5471
|
-
164,
|
|
5472
|
-
165,
|
|
5473
|
-
166,
|
|
5474
|
-
167,
|
|
5475
|
-
168,
|
|
5476
|
-
169,
|
|
5477
|
-
170,
|
|
5478
|
-
171,
|
|
5479
|
-
172,
|
|
5480
|
-
173,
|
|
5481
|
-
178,
|
|
5482
|
-
179,
|
|
5483
|
-
184,
|
|
5484
|
-
185,
|
|
5485
|
-
196,
|
|
5486
|
-
197,
|
|
5487
|
-
198,
|
|
5488
|
-
199,
|
|
5489
|
-
200,
|
|
5490
|
-
201,
|
|
5491
|
-
202,
|
|
5492
|
-
203,
|
|
5493
|
-
204,
|
|
5494
|
-
205,
|
|
5495
|
-
206,
|
|
5496
|
-
207,
|
|
5497
|
-
208,
|
|
5498
|
-
209,
|
|
5499
|
-
214,
|
|
5500
|
-
215,
|
|
5501
|
-
220,
|
|
5502
|
-
221
|
|
5503
|
-
];
|
|
5504
|
-
}
|
|
5505
|
-
} catch (error) {
|
|
5506
|
-
}
|
|
5507
|
-
exports.inspectOpts = Object.keys(process.env).filter((key) => {
|
|
5508
|
-
return /^debug_/i.test(key);
|
|
5509
|
-
}).reduce((obj, key) => {
|
|
5510
|
-
const prop = key.substring(6).toLowerCase().replace(/_([a-z])/g, (_, k) => {
|
|
5511
|
-
return k.toUpperCase();
|
|
5512
|
-
});
|
|
5513
|
-
let val = process.env[key];
|
|
5514
|
-
if (/^(yes|on|true|enabled)$/i.test(val)) {
|
|
5515
|
-
val = true;
|
|
5516
|
-
} else if (/^(no|off|false|disabled)$/i.test(val)) {
|
|
5517
|
-
val = false;
|
|
5518
|
-
} else if (val === "null") {
|
|
5519
|
-
val = null;
|
|
5520
|
-
} else {
|
|
5521
|
-
val = Number(val);
|
|
5522
|
-
}
|
|
5523
|
-
obj[prop] = val;
|
|
5524
|
-
return obj;
|
|
5525
|
-
}, {});
|
|
5526
|
-
function useColors() {
|
|
5527
|
-
return "colors" in exports.inspectOpts ? Boolean(exports.inspectOpts.colors) : tty.isatty(process.stderr.fd);
|
|
5528
|
-
}
|
|
5529
|
-
function formatArgs(args) {
|
|
5530
|
-
const { namespace: name, useColors: useColors2 } = this;
|
|
5531
|
-
if (useColors2) {
|
|
5532
|
-
const c = this.color;
|
|
5533
|
-
const colorCode = "\x1B[3" + (c < 8 ? c : "8;5;" + c);
|
|
5534
|
-
const prefix = ` ${colorCode};1m${name} \x1B[0m`;
|
|
5535
|
-
args[0] = prefix + args[0].split("\n").join("\n" + prefix);
|
|
5536
|
-
args.push(colorCode + "m+" + module.exports.humanize(this.diff) + "\x1B[0m");
|
|
5537
|
-
} else {
|
|
5538
|
-
args[0] = getDate() + name + " " + args[0];
|
|
5539
|
-
}
|
|
5540
|
-
}
|
|
5541
|
-
function getDate() {
|
|
5542
|
-
if (exports.inspectOpts.hideDate) {
|
|
5543
|
-
return "";
|
|
5544
|
-
}
|
|
5545
|
-
return (/* @__PURE__ */ new Date()).toISOString() + " ";
|
|
5546
|
-
}
|
|
5547
|
-
function log(...args) {
|
|
5548
|
-
return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + "\n");
|
|
5549
|
-
}
|
|
5550
|
-
function save(namespaces) {
|
|
5551
|
-
if (namespaces) {
|
|
5552
|
-
process.env.DEBUG = namespaces;
|
|
5553
|
-
} else {
|
|
5554
|
-
delete process.env.DEBUG;
|
|
5555
|
-
}
|
|
5556
|
-
}
|
|
5557
|
-
function load() {
|
|
5558
|
-
return process.env.DEBUG;
|
|
5559
|
-
}
|
|
5560
|
-
function init(debug) {
|
|
5561
|
-
debug.inspectOpts = {};
|
|
5562
|
-
const keys = Object.keys(exports.inspectOpts);
|
|
5563
|
-
for (let i = 0; i < keys.length; i++) {
|
|
5564
|
-
debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
|
|
5565
|
-
}
|
|
5566
|
-
}
|
|
5567
|
-
module.exports = require_common()(exports);
|
|
5568
|
-
var { formatters } = module.exports;
|
|
5569
|
-
formatters.o = function(v) {
|
|
5570
|
-
this.inspectOpts.colors = this.useColors;
|
|
5571
|
-
return util.inspect(v, this.inspectOpts).split("\n").map((str) => str.trim()).join(" ");
|
|
5572
|
-
};
|
|
5573
|
-
formatters.O = function(v) {
|
|
5574
|
-
this.inspectOpts.colors = this.useColors;
|
|
5575
|
-
return util.inspect(v, this.inspectOpts);
|
|
5576
|
-
};
|
|
5577
|
-
}
|
|
5578
|
-
});
|
|
5579
|
-
|
|
5580
|
-
// ../../node_modules/debug/src/index.js
|
|
5581
|
-
var require_src = __commonJS({
|
|
5582
|
-
"../../node_modules/debug/src/index.js"(exports, module) {
|
|
5583
|
-
if (typeof process === "undefined" || process.type === "renderer" || process.browser === true || process.__nwjs) {
|
|
5584
|
-
module.exports = require_browser();
|
|
5585
|
-
} else {
|
|
5586
|
-
module.exports = require_node();
|
|
5587
|
-
}
|
|
5588
|
-
}
|
|
5589
|
-
});
|
|
5590
|
-
|
|
5591
|
-
// ../../node_modules/follow-redirects/debug.js
|
|
5592
|
-
var require_debug = __commonJS({
|
|
5593
|
-
"../../node_modules/follow-redirects/debug.js"(exports, module) {
|
|
5594
|
-
var debug;
|
|
5595
|
-
module.exports = function() {
|
|
5596
|
-
if (!debug) {
|
|
5597
|
-
try {
|
|
5598
|
-
debug = require_src()("follow-redirects");
|
|
5599
|
-
} catch (error) {
|
|
5600
|
-
}
|
|
5601
|
-
if (typeof debug !== "function") {
|
|
5602
|
-
debug = function() {
|
|
5603
|
-
};
|
|
5604
|
-
}
|
|
5605
|
-
}
|
|
5606
|
-
debug.apply(null, arguments);
|
|
5607
|
-
};
|
|
5608
|
-
}
|
|
5609
|
-
});
|
|
5610
|
-
|
|
5611
|
-
// ../../node_modules/follow-redirects/index.js
|
|
5612
|
-
var require_follow_redirects = __commonJS({
|
|
5613
|
-
"../../node_modules/follow-redirects/index.js"(exports, module) {
|
|
5614
|
-
var url = __require("url");
|
|
5615
|
-
var URL2 = url.URL;
|
|
5616
|
-
var http = __require("http");
|
|
5617
|
-
var https = __require("https");
|
|
5618
|
-
var Writable = __require("stream").Writable;
|
|
5619
|
-
var assert = __require("assert");
|
|
5620
|
-
var debug = require_debug();
|
|
5621
|
-
(function detectUnsupportedEnvironment() {
|
|
5622
|
-
var looksLikeNode = typeof process !== "undefined";
|
|
5623
|
-
var looksLikeBrowser = typeof window !== "undefined" && typeof document !== "undefined";
|
|
5624
|
-
var looksLikeV8 = isFunction(Error.captureStackTrace);
|
|
5625
|
-
if (!looksLikeNode && (looksLikeBrowser || !looksLikeV8)) {
|
|
5626
|
-
console.warn("The follow-redirects package should be excluded from browser builds.");
|
|
5627
|
-
}
|
|
5628
|
-
})();
|
|
5629
|
-
var useNativeURL = false;
|
|
5630
|
-
try {
|
|
5631
|
-
assert(new URL2(""));
|
|
5632
|
-
} catch (error) {
|
|
5633
|
-
useNativeURL = error.code === "ERR_INVALID_URL";
|
|
5634
|
-
}
|
|
5635
|
-
var sensitiveHeaders = [
|
|
5636
|
-
"Authorization",
|
|
5637
|
-
"Proxy-Authorization",
|
|
5638
|
-
"Cookie"
|
|
5639
|
-
];
|
|
5640
|
-
var preservedUrlFields = [
|
|
5641
|
-
"auth",
|
|
5642
|
-
"host",
|
|
5643
|
-
"hostname",
|
|
5644
|
-
"href",
|
|
5645
|
-
"path",
|
|
5646
|
-
"pathname",
|
|
5647
|
-
"port",
|
|
5648
|
-
"protocol",
|
|
5649
|
-
"query",
|
|
5650
|
-
"search",
|
|
5651
|
-
"hash"
|
|
5652
|
-
];
|
|
5653
|
-
var events = ["abort", "aborted", "connect", "error", "socket", "timeout"];
|
|
5654
|
-
var eventHandlers = /* @__PURE__ */ Object.create(null);
|
|
5655
|
-
events.forEach(function(event) {
|
|
5656
|
-
eventHandlers[event] = function(arg1, arg2, arg3) {
|
|
5657
|
-
this._redirectable.emit(event, arg1, arg2, arg3);
|
|
5658
|
-
};
|
|
5659
|
-
});
|
|
5660
|
-
var InvalidUrlError = createErrorType(
|
|
5661
|
-
"ERR_INVALID_URL",
|
|
5662
|
-
"Invalid URL",
|
|
5663
|
-
TypeError
|
|
5664
|
-
);
|
|
5665
|
-
var RedirectionError = createErrorType(
|
|
5666
|
-
"ERR_FR_REDIRECTION_FAILURE",
|
|
5667
|
-
"Redirected request failed"
|
|
5668
|
-
);
|
|
5669
|
-
var TooManyRedirectsError = createErrorType(
|
|
5670
|
-
"ERR_FR_TOO_MANY_REDIRECTS",
|
|
5671
|
-
"Maximum number of redirects exceeded",
|
|
5672
|
-
RedirectionError
|
|
5673
|
-
);
|
|
5674
|
-
var MaxBodyLengthExceededError = createErrorType(
|
|
5675
|
-
"ERR_FR_MAX_BODY_LENGTH_EXCEEDED",
|
|
5676
|
-
"Request body larger than maxBodyLength limit"
|
|
5677
|
-
);
|
|
5678
|
-
var WriteAfterEndError = createErrorType(
|
|
5679
|
-
"ERR_STREAM_WRITE_AFTER_END",
|
|
5680
|
-
"write after end"
|
|
5681
|
-
);
|
|
5682
|
-
var destroy = Writable.prototype.destroy || noop;
|
|
5683
|
-
function RedirectableRequest(options, responseCallback) {
|
|
5684
|
-
Writable.call(this);
|
|
5685
|
-
this._sanitizeOptions(options);
|
|
5686
|
-
this._options = options;
|
|
5687
|
-
this._ended = false;
|
|
5688
|
-
this._ending = false;
|
|
5689
|
-
this._redirectCount = 0;
|
|
5690
|
-
this._redirects = [];
|
|
5691
|
-
this._requestBodyLength = 0;
|
|
5692
|
-
this._requestBodyBuffers = [];
|
|
5693
|
-
if (responseCallback) {
|
|
5694
|
-
this.on("response", responseCallback);
|
|
5695
|
-
}
|
|
5696
|
-
var self = this;
|
|
5697
|
-
this._onNativeResponse = function(response) {
|
|
5698
|
-
try {
|
|
5699
|
-
self._processResponse(response);
|
|
5700
|
-
} catch (cause) {
|
|
5701
|
-
self.emit("error", cause instanceof RedirectionError ? cause : new RedirectionError({ cause }));
|
|
5702
|
-
}
|
|
5703
|
-
};
|
|
5704
|
-
this._headerFilter = new RegExp("^(?:" + sensitiveHeaders.concat(options.sensitiveHeaders).map(escapeRegex).join("|") + ")$", "i");
|
|
5705
|
-
this._performRequest();
|
|
5706
|
-
}
|
|
5707
|
-
RedirectableRequest.prototype = Object.create(Writable.prototype);
|
|
5708
|
-
RedirectableRequest.prototype.abort = function() {
|
|
5709
|
-
destroyRequest(this._currentRequest);
|
|
5710
|
-
this._currentRequest.abort();
|
|
5711
|
-
this.emit("abort");
|
|
5712
|
-
};
|
|
5713
|
-
RedirectableRequest.prototype.destroy = function(error) {
|
|
5714
|
-
destroyRequest(this._currentRequest, error);
|
|
5715
|
-
destroy.call(this, error);
|
|
5716
|
-
return this;
|
|
5717
|
-
};
|
|
5718
|
-
RedirectableRequest.prototype.write = function(data, encoding, callback) {
|
|
5719
|
-
if (this._ending) {
|
|
5720
|
-
throw new WriteAfterEndError();
|
|
5721
|
-
}
|
|
5722
|
-
if (!isString(data) && !isBuffer(data)) {
|
|
5723
|
-
throw new TypeError("data should be a string, Buffer or Uint8Array");
|
|
5724
|
-
}
|
|
5725
|
-
if (isFunction(encoding)) {
|
|
5726
|
-
callback = encoding;
|
|
5727
|
-
encoding = null;
|
|
5728
|
-
}
|
|
5729
|
-
if (data.length === 0) {
|
|
5730
|
-
if (callback) {
|
|
5731
|
-
callback();
|
|
5732
|
-
}
|
|
5733
|
-
return;
|
|
5734
|
-
}
|
|
5735
|
-
if (this._requestBodyLength + data.length <= this._options.maxBodyLength) {
|
|
5736
|
-
this._requestBodyLength += data.length;
|
|
5737
|
-
this._requestBodyBuffers.push({ data, encoding });
|
|
5738
|
-
this._currentRequest.write(data, encoding, callback);
|
|
5739
|
-
} else {
|
|
5740
|
-
this.emit("error", new MaxBodyLengthExceededError());
|
|
5741
|
-
this.abort();
|
|
5742
|
-
}
|
|
5743
|
-
};
|
|
5744
|
-
RedirectableRequest.prototype.end = function(data, encoding, callback) {
|
|
5745
|
-
if (isFunction(data)) {
|
|
5746
|
-
callback = data;
|
|
5747
|
-
data = encoding = null;
|
|
5748
|
-
} else if (isFunction(encoding)) {
|
|
5749
|
-
callback = encoding;
|
|
5750
|
-
encoding = null;
|
|
5751
|
-
}
|
|
5752
|
-
if (!data) {
|
|
5753
|
-
this._ended = this._ending = true;
|
|
5754
|
-
this._currentRequest.end(null, null, callback);
|
|
5755
|
-
} else {
|
|
5756
|
-
var self = this;
|
|
5757
|
-
var currentRequest = this._currentRequest;
|
|
5758
|
-
this.write(data, encoding, function() {
|
|
5759
|
-
self._ended = true;
|
|
5760
|
-
currentRequest.end(null, null, callback);
|
|
5761
|
-
});
|
|
5762
|
-
this._ending = true;
|
|
5763
|
-
}
|
|
5764
|
-
};
|
|
5765
|
-
RedirectableRequest.prototype.setHeader = function(name, value) {
|
|
5766
|
-
this._options.headers[name] = value;
|
|
5767
|
-
this._currentRequest.setHeader(name, value);
|
|
5768
|
-
};
|
|
5769
|
-
RedirectableRequest.prototype.removeHeader = function(name) {
|
|
5770
|
-
delete this._options.headers[name];
|
|
5771
|
-
this._currentRequest.removeHeader(name);
|
|
5772
|
-
};
|
|
5773
|
-
RedirectableRequest.prototype.setTimeout = function(msecs, callback) {
|
|
5774
|
-
var self = this;
|
|
5775
|
-
function destroyOnTimeout(socket) {
|
|
5776
|
-
socket.setTimeout(msecs);
|
|
5777
|
-
socket.removeListener("timeout", socket.destroy);
|
|
5778
|
-
socket.addListener("timeout", socket.destroy);
|
|
5779
|
-
}
|
|
5780
|
-
function startTimer(socket) {
|
|
5781
|
-
if (self._timeout) {
|
|
5782
|
-
clearTimeout(self._timeout);
|
|
5783
|
-
}
|
|
5784
|
-
self._timeout = setTimeout(function() {
|
|
5785
|
-
self.emit("timeout");
|
|
5786
|
-
clearTimer();
|
|
5787
|
-
}, msecs);
|
|
5788
|
-
destroyOnTimeout(socket);
|
|
5789
|
-
}
|
|
5790
|
-
function clearTimer() {
|
|
5791
|
-
if (self._timeout) {
|
|
5792
|
-
clearTimeout(self._timeout);
|
|
5793
|
-
self._timeout = null;
|
|
5794
|
-
}
|
|
5795
|
-
self.removeListener("abort", clearTimer);
|
|
5796
|
-
self.removeListener("error", clearTimer);
|
|
5797
|
-
self.removeListener("response", clearTimer);
|
|
5798
|
-
self.removeListener("close", clearTimer);
|
|
5799
|
-
if (callback) {
|
|
5800
|
-
self.removeListener("timeout", callback);
|
|
5801
|
-
}
|
|
5802
|
-
if (!self.socket) {
|
|
5803
|
-
self._currentRequest.removeListener("socket", startTimer);
|
|
5804
|
-
}
|
|
5805
|
-
}
|
|
5806
|
-
if (callback) {
|
|
5807
|
-
this.on("timeout", callback);
|
|
5808
|
-
}
|
|
5809
|
-
if (this.socket) {
|
|
5810
|
-
startTimer(this.socket);
|
|
5811
|
-
} else {
|
|
5812
|
-
this._currentRequest.once("socket", startTimer);
|
|
5813
|
-
}
|
|
5814
|
-
this.on("socket", destroyOnTimeout);
|
|
5815
|
-
this.on("abort", clearTimer);
|
|
5816
|
-
this.on("error", clearTimer);
|
|
5817
|
-
this.on("response", clearTimer);
|
|
5818
|
-
this.on("close", clearTimer);
|
|
5819
|
-
return this;
|
|
5820
|
-
};
|
|
5821
|
-
[
|
|
5822
|
-
"flushHeaders",
|
|
5823
|
-
"getHeader",
|
|
5824
|
-
"setNoDelay",
|
|
5825
|
-
"setSocketKeepAlive"
|
|
5826
|
-
].forEach(function(method) {
|
|
5827
|
-
RedirectableRequest.prototype[method] = function(a, b) {
|
|
5828
|
-
return this._currentRequest[method](a, b);
|
|
5829
|
-
};
|
|
5830
|
-
});
|
|
5831
|
-
["aborted", "connection", "socket"].forEach(function(property) {
|
|
5832
|
-
Object.defineProperty(RedirectableRequest.prototype, property, {
|
|
5833
|
-
get: function() {
|
|
5834
|
-
return this._currentRequest[property];
|
|
5835
|
-
}
|
|
5836
|
-
});
|
|
5837
|
-
});
|
|
5838
|
-
RedirectableRequest.prototype._sanitizeOptions = function(options) {
|
|
5839
|
-
if (!options.headers) {
|
|
5840
|
-
options.headers = {};
|
|
5841
|
-
}
|
|
5842
|
-
if (!isArray(options.sensitiveHeaders)) {
|
|
5843
|
-
options.sensitiveHeaders = [];
|
|
5844
|
-
}
|
|
5845
|
-
if (options.host) {
|
|
5846
|
-
if (!options.hostname) {
|
|
5847
|
-
options.hostname = options.host;
|
|
5848
|
-
}
|
|
5849
|
-
delete options.host;
|
|
5850
|
-
}
|
|
5851
|
-
if (!options.pathname && options.path) {
|
|
5852
|
-
var searchPos = options.path.indexOf("?");
|
|
5853
|
-
if (searchPos < 0) {
|
|
5854
|
-
options.pathname = options.path;
|
|
5855
|
-
} else {
|
|
5856
|
-
options.pathname = options.path.substring(0, searchPos);
|
|
5857
|
-
options.search = options.path.substring(searchPos);
|
|
5858
|
-
}
|
|
5859
|
-
}
|
|
5860
|
-
};
|
|
5861
|
-
RedirectableRequest.prototype._performRequest = function() {
|
|
5862
|
-
var protocol = this._options.protocol;
|
|
5863
|
-
var nativeProtocol = this._options.nativeProtocols[protocol];
|
|
5864
|
-
if (!nativeProtocol) {
|
|
5865
|
-
throw new TypeError("Unsupported protocol " + protocol);
|
|
5866
|
-
}
|
|
5867
|
-
if (this._options.agents) {
|
|
5868
|
-
var scheme = protocol.slice(0, -1);
|
|
5869
|
-
this._options.agent = this._options.agents[scheme];
|
|
5870
|
-
}
|
|
5871
|
-
var request = this._currentRequest = nativeProtocol.request(this._options, this._onNativeResponse);
|
|
5872
|
-
request._redirectable = this;
|
|
5873
|
-
for (var event of events) {
|
|
5874
|
-
request.on(event, eventHandlers[event]);
|
|
5875
|
-
}
|
|
5876
|
-
this._currentUrl = /^\//.test(this._options.path) ? url.format(this._options) : (
|
|
5877
|
-
// When making a request to a proxy, […]
|
|
5878
|
-
// a client MUST send the target URI in absolute-form […].
|
|
5879
|
-
this._options.path
|
|
5880
|
-
);
|
|
5881
|
-
if (this._isRedirect) {
|
|
5882
|
-
var i = 0;
|
|
5883
|
-
var self = this;
|
|
5884
|
-
var buffers = this._requestBodyBuffers;
|
|
5885
|
-
(function writeNext(error) {
|
|
5886
|
-
if (request === self._currentRequest) {
|
|
5887
|
-
if (error) {
|
|
5888
|
-
self.emit("error", error);
|
|
5889
|
-
} else if (i < buffers.length) {
|
|
5890
|
-
var buffer = buffers[i++];
|
|
5891
|
-
if (!request.finished) {
|
|
5892
|
-
request.write(buffer.data, buffer.encoding, writeNext);
|
|
5893
|
-
}
|
|
5894
|
-
} else if (self._ended) {
|
|
5895
|
-
request.end();
|
|
5896
|
-
}
|
|
5897
|
-
}
|
|
5898
|
-
})();
|
|
5899
|
-
}
|
|
5900
|
-
};
|
|
5901
|
-
RedirectableRequest.prototype._processResponse = function(response) {
|
|
5902
|
-
var statusCode = response.statusCode;
|
|
5903
|
-
if (this._options.trackRedirects) {
|
|
5904
|
-
this._redirects.push({
|
|
5905
|
-
url: this._currentUrl,
|
|
5906
|
-
headers: response.headers,
|
|
5907
|
-
statusCode
|
|
5908
|
-
});
|
|
5909
|
-
}
|
|
5910
|
-
var location = response.headers.location;
|
|
5911
|
-
if (!location || this._options.followRedirects === false || statusCode < 300 || statusCode >= 400) {
|
|
5912
|
-
response.responseUrl = this._currentUrl;
|
|
5913
|
-
response.redirects = this._redirects;
|
|
5914
|
-
this.emit("response", response);
|
|
5915
|
-
this._requestBodyBuffers = [];
|
|
5916
|
-
return;
|
|
5917
|
-
}
|
|
5918
|
-
destroyRequest(this._currentRequest);
|
|
5919
|
-
response.destroy();
|
|
5920
|
-
if (++this._redirectCount > this._options.maxRedirects) {
|
|
5921
|
-
throw new TooManyRedirectsError();
|
|
5922
|
-
}
|
|
5923
|
-
var requestHeaders;
|
|
5924
|
-
var beforeRedirect = this._options.beforeRedirect;
|
|
5925
|
-
if (beforeRedirect) {
|
|
5926
|
-
requestHeaders = Object.assign({
|
|
5927
|
-
// The Host header was set by nativeProtocol.request
|
|
5928
|
-
Host: response.req.getHeader("host")
|
|
5929
|
-
}, this._options.headers);
|
|
5930
|
-
}
|
|
5931
|
-
var method = this._options.method;
|
|
5932
|
-
if ((statusCode === 301 || statusCode === 302) && this._options.method === "POST" || // RFC7231§6.4.4: The 303 (See Other) status code indicates that
|
|
5933
|
-
// the server is redirecting the user agent to a different resource […]
|
|
5934
|
-
// A user agent can perform a retrieval request targeting that URI
|
|
5935
|
-
// (a GET or HEAD request if using HTTP) […]
|
|
5936
|
-
statusCode === 303 && !/^(?:GET|HEAD)$/.test(this._options.method)) {
|
|
5937
|
-
this._options.method = "GET";
|
|
5938
|
-
this._requestBodyBuffers = [];
|
|
5939
|
-
removeMatchingHeaders(/^content-/i, this._options.headers);
|
|
5940
|
-
}
|
|
5941
|
-
var currentHostHeader = removeMatchingHeaders(/^host$/i, this._options.headers);
|
|
5942
|
-
var currentUrlParts = parseUrl(this._currentUrl);
|
|
5943
|
-
var currentHost = currentHostHeader || currentUrlParts.host;
|
|
5944
|
-
var currentUrl = /^\w+:/.test(location) ? this._currentUrl : url.format(Object.assign(currentUrlParts, { host: currentHost }));
|
|
5945
|
-
var redirectUrl = resolveUrl(location, currentUrl);
|
|
5946
|
-
debug("redirecting to", redirectUrl.href);
|
|
5947
|
-
this._isRedirect = true;
|
|
5948
|
-
spreadUrlObject(redirectUrl, this._options);
|
|
5949
|
-
if (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== "https:" || redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost)) {
|
|
5950
|
-
removeMatchingHeaders(this._headerFilter, this._options.headers);
|
|
5951
|
-
}
|
|
5952
|
-
if (isFunction(beforeRedirect)) {
|
|
5953
|
-
var responseDetails = {
|
|
5954
|
-
headers: response.headers,
|
|
5955
|
-
statusCode
|
|
5956
|
-
};
|
|
5957
|
-
var requestDetails = {
|
|
5958
|
-
url: currentUrl,
|
|
5959
|
-
method,
|
|
5960
|
-
headers: requestHeaders
|
|
5961
|
-
};
|
|
5962
|
-
beforeRedirect(this._options, responseDetails, requestDetails);
|
|
5963
|
-
this._sanitizeOptions(this._options);
|
|
5964
|
-
}
|
|
5965
|
-
this._performRequest();
|
|
5966
|
-
};
|
|
5967
|
-
function wrap(protocols) {
|
|
5968
|
-
var exports2 = {
|
|
5969
|
-
maxRedirects: 21,
|
|
5970
|
-
maxBodyLength: 10 * 1024 * 1024
|
|
5971
|
-
};
|
|
5972
|
-
var nativeProtocols = {};
|
|
5973
|
-
Object.keys(protocols).forEach(function(scheme) {
|
|
5974
|
-
var protocol = scheme + ":";
|
|
5975
|
-
var nativeProtocol = nativeProtocols[protocol] = protocols[scheme];
|
|
5976
|
-
var wrappedProtocol = exports2[scheme] = Object.create(nativeProtocol);
|
|
5977
|
-
function request(input, options, callback) {
|
|
5978
|
-
if (isURL(input)) {
|
|
5979
|
-
input = spreadUrlObject(input);
|
|
5980
|
-
} else if (isString(input)) {
|
|
5981
|
-
input = spreadUrlObject(parseUrl(input));
|
|
5982
|
-
} else {
|
|
5983
|
-
callback = options;
|
|
5984
|
-
options = validateUrl(input);
|
|
5985
|
-
input = { protocol };
|
|
5986
|
-
}
|
|
5987
|
-
if (isFunction(options)) {
|
|
5988
|
-
callback = options;
|
|
5989
|
-
options = null;
|
|
5990
|
-
}
|
|
5991
|
-
options = Object.assign({
|
|
5992
|
-
maxRedirects: exports2.maxRedirects,
|
|
5993
|
-
maxBodyLength: exports2.maxBodyLength
|
|
5994
|
-
}, input, options);
|
|
5995
|
-
options.nativeProtocols = nativeProtocols;
|
|
5996
|
-
if (!isString(options.host) && !isString(options.hostname)) {
|
|
5997
|
-
options.hostname = "::1";
|
|
5998
|
-
}
|
|
5999
|
-
assert.equal(options.protocol, protocol, "protocol mismatch");
|
|
6000
|
-
debug("options", options);
|
|
6001
|
-
return new RedirectableRequest(options, callback);
|
|
6002
|
-
}
|
|
6003
|
-
function get(input, options, callback) {
|
|
6004
|
-
var wrappedRequest = wrappedProtocol.request(input, options, callback);
|
|
6005
|
-
wrappedRequest.end();
|
|
6006
|
-
return wrappedRequest;
|
|
6007
|
-
}
|
|
6008
|
-
Object.defineProperties(wrappedProtocol, {
|
|
6009
|
-
request: { value: request, configurable: true, enumerable: true, writable: true },
|
|
6010
|
-
get: { value: get, configurable: true, enumerable: true, writable: true }
|
|
6011
|
-
});
|
|
6012
|
-
});
|
|
6013
|
-
return exports2;
|
|
6014
|
-
}
|
|
6015
|
-
function noop() {
|
|
6016
|
-
}
|
|
6017
|
-
function parseUrl(input) {
|
|
6018
|
-
var parsed;
|
|
6019
|
-
if (useNativeURL) {
|
|
6020
|
-
parsed = new URL2(input);
|
|
6021
|
-
} else {
|
|
6022
|
-
parsed = validateUrl(url.parse(input));
|
|
6023
|
-
if (!isString(parsed.protocol)) {
|
|
6024
|
-
throw new InvalidUrlError({ input });
|
|
6025
|
-
}
|
|
6026
|
-
}
|
|
6027
|
-
return parsed;
|
|
6028
|
-
}
|
|
6029
|
-
function resolveUrl(relative, base) {
|
|
6030
|
-
return useNativeURL ? new URL2(relative, base) : parseUrl(url.resolve(base, relative));
|
|
6031
|
-
}
|
|
6032
|
-
function validateUrl(input) {
|
|
6033
|
-
if (/^\[/.test(input.hostname) && !/^\[[:0-9a-f]+\]$/i.test(input.hostname)) {
|
|
6034
|
-
throw new InvalidUrlError({ input: input.href || input });
|
|
6035
|
-
}
|
|
6036
|
-
if (/^\[/.test(input.host) && !/^\[[:0-9a-f]+\](:\d+)?$/i.test(input.host)) {
|
|
6037
|
-
throw new InvalidUrlError({ input: input.href || input });
|
|
6038
|
-
}
|
|
6039
|
-
return input;
|
|
4979
|
+
originalPrompt: context.originalPrompt,
|
|
4980
|
+
contract: context.contract,
|
|
4981
|
+
designSystemSummary: context.designContext
|
|
4982
|
+
});
|
|
4983
|
+
const numberedSource = context.sourceCode.split("\n").map((line, i) => `${String(i + 1).padStart(4)} | ${line}`).join("\n");
|
|
4984
|
+
const agent = createAgent({
|
|
4985
|
+
provider: routerProvider,
|
|
4986
|
+
routeOverride: config.routeOverride,
|
|
4987
|
+
onRetry: config.onRetry
|
|
4988
|
+
});
|
|
4989
|
+
const evalStart = Date.now();
|
|
4990
|
+
const totalCriteriaCount = TIER_1_CRITERIA.length + TIER_2_CRITERIA.length;
|
|
4991
|
+
const results = await Promise.all([
|
|
4992
|
+
...TIER_1_CRITERIA.map((c) => evalCriterion(c, 1, motherPrompt, numberedSource, agent, model)),
|
|
4993
|
+
...TIER_2_CRITERIA.map((c) => evalCriterion(c, 2, motherPrompt, numberedSource, agent, model))
|
|
4994
|
+
]);
|
|
4995
|
+
const allIssues = [];
|
|
4996
|
+
const passCategories = [];
|
|
4997
|
+
let totalIn = 0;
|
|
4998
|
+
let totalOut = 0;
|
|
4999
|
+
let cachedTokensEstimate = 0;
|
|
5000
|
+
for (const r of results) {
|
|
5001
|
+
allIssues.push(...r.issues);
|
|
5002
|
+
if (r.pass) {
|
|
5003
|
+
passCategories.push(r.criterion);
|
|
6040
5004
|
}
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
5005
|
+
totalIn += r.tokens.in;
|
|
5006
|
+
totalOut += r.tokens.out;
|
|
5007
|
+
}
|
|
5008
|
+
const firstResult = results[0];
|
|
5009
|
+
if (firstResult && firstResult.tokens.in > 0) {
|
|
5010
|
+
cachedTokensEstimate = firstResult.tokens.in * (totalCriteriaCount - 1);
|
|
5011
|
+
}
|
|
5012
|
+
const wallMs = Date.now() - evalStart;
|
|
5013
|
+
for (const r of results) {
|
|
5014
|
+
const issueCount = r.issues.length;
|
|
5015
|
+
const status = r.pass ? "PASS" : r.tier === 1 ? "FAIL" : r.issues.some((i) => i.result === "fail") ? "FAIL" : "WARN";
|
|
5016
|
+
const issueLabel = issueCount > 0 ? ` (${issueCount} issue${issueCount > 1 ? "s" : ""})` : "";
|
|
5017
|
+
console.log(`[eval] ${r.criterion}: ${status}${issueLabel} ${(r.durationMs / 1e3).toFixed(1)}s`);
|
|
5018
|
+
}
|
|
5019
|
+
console.log(
|
|
5020
|
+
`[eval] total: ${(wallMs / 1e3).toFixed(1)}s wall (${totalCriteriaCount} parallel) | in=${totalIn} out=${totalOut} cached~=${cachedTokensEstimate} | issues=${allIssues.length} pass=${passCategories.length}`
|
|
5021
|
+
);
|
|
5022
|
+
return {
|
|
5023
|
+
issues: allIssues,
|
|
5024
|
+
pass: passCategories,
|
|
5025
|
+
inputTokens: totalIn,
|
|
5026
|
+
outputTokens: totalOut
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5029
|
+
var TIER_1_CRITERIA, TIER_2_CRITERIA, TIER_1_CATEGORIES, TIER_2_CATEGORIES, VALID_CATEGORIES;
|
|
5030
|
+
var init_llm_evaluator = __esm({
|
|
5031
|
+
"src/evaluation/llm-evaluator.ts"() {
|
|
5032
|
+
init_llm_router();
|
|
5033
|
+
init_types_public();
|
|
5034
|
+
TIER_1_CRITERIA = ["functionality", "crash"];
|
|
5035
|
+
TIER_2_CRITERIA = ["interactivity", "accessibility", "layout", "loading", "visual"];
|
|
5036
|
+
TIER_1_CATEGORIES = /* @__PURE__ */ new Set(["functionality", "crash"]);
|
|
5037
|
+
TIER_2_CATEGORIES = /* @__PURE__ */ new Set([
|
|
5038
|
+
"interactivity",
|
|
5039
|
+
"accessibility",
|
|
5040
|
+
"layout",
|
|
5041
|
+
"loading",
|
|
5042
|
+
"visual"
|
|
5043
|
+
]);
|
|
5044
|
+
VALID_CATEGORIES = /* @__PURE__ */ new Set([
|
|
5045
|
+
...TIER_1_CATEGORIES,
|
|
5046
|
+
...TIER_2_CATEGORIES
|
|
5047
|
+
]);
|
|
5048
|
+
}
|
|
5049
|
+
});
|
|
5050
|
+
|
|
5051
|
+
// src/evaluation/cost-tracker.ts
|
|
5052
|
+
var cost_tracker_exports = {};
|
|
5053
|
+
__export(cost_tracker_exports, {
|
|
5054
|
+
CostTracker: () => CostTracker,
|
|
5055
|
+
pricePer1k: () => pricePer1k
|
|
5056
|
+
});
|
|
5057
|
+
function resolveRegistryId(model) {
|
|
5058
|
+
const keys = Object.keys(MODEL_REGISTRY);
|
|
5059
|
+
if (keys.includes(model)) return model;
|
|
5060
|
+
const bySuffix = keys.find((id) => id.endsWith(`/${model}`));
|
|
5061
|
+
if (bySuffix) return bySuffix;
|
|
5062
|
+
const undated = model.replace(/-\d{8}$/, "");
|
|
5063
|
+
return keys.find((id) => id.endsWith(`/${undated}`)) ?? null;
|
|
5064
|
+
}
|
|
5065
|
+
function pricePer1k(model) {
|
|
5066
|
+
const id = resolveRegistryId(model);
|
|
5067
|
+
if (id === null) return FALLBACK_PER_1K;
|
|
5068
|
+
const { costs } = MODEL_REGISTRY[id];
|
|
5069
|
+
return { input: costs.inputPer1M / 1e3, output: costs.outputPer1M / 1e3 };
|
|
5070
|
+
}
|
|
5071
|
+
var FALLBACK_PER_1K, CostTracker;
|
|
5072
|
+
var init_cost_tracker = __esm({
|
|
5073
|
+
"src/evaluation/cost-tracker.ts"() {
|
|
5074
|
+
FALLBACK_PER_1K = { input: 3e-3, output: 0.015 };
|
|
5075
|
+
CostTracker = class {
|
|
5076
|
+
constructor(maxBudget) {
|
|
5077
|
+
this.maxBudget = maxBudget;
|
|
6048
5078
|
}
|
|
6049
|
-
|
|
6050
|
-
|
|
5079
|
+
maxBudget;
|
|
5080
|
+
totalCost = 0;
|
|
5081
|
+
record(model, inputTokens, outputTokens) {
|
|
5082
|
+
const prices = pricePer1k(model);
|
|
5083
|
+
const cost = inputTokens / 1e3 * prices.input + outputTokens / 1e3 * prices.output;
|
|
5084
|
+
this.totalCost += cost;
|
|
5085
|
+
return cost;
|
|
6051
5086
|
}
|
|
6052
|
-
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
function removeMatchingHeaders(regex, headers) {
|
|
6056
|
-
var lastValue;
|
|
6057
|
-
for (var header in headers) {
|
|
6058
|
-
if (regex.test(header)) {
|
|
6059
|
-
lastValue = headers[header];
|
|
6060
|
-
delete headers[header];
|
|
6061
|
-
}
|
|
5087
|
+
canContinue() {
|
|
5088
|
+
if (this.maxBudget === null) return true;
|
|
5089
|
+
return this.totalCost < this.maxBudget;
|
|
6062
5090
|
}
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
function createErrorType(code, message, baseClass) {
|
|
6066
|
-
function CustomError(properties) {
|
|
6067
|
-
if (isFunction(Error.captureStackTrace)) {
|
|
6068
|
-
Error.captureStackTrace(this, this.constructor);
|
|
6069
|
-
}
|
|
6070
|
-
Object.assign(this, properties || {});
|
|
6071
|
-
this.code = code;
|
|
6072
|
-
this.message = this.cause ? message + ": " + this.cause.message : message;
|
|
5091
|
+
getTotal() {
|
|
5092
|
+
return this.totalCost;
|
|
6073
5093
|
}
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
value: CustomError,
|
|
6078
|
-
enumerable: false
|
|
6079
|
-
},
|
|
6080
|
-
name: {
|
|
6081
|
-
value: "Error [" + code + "]",
|
|
6082
|
-
enumerable: false
|
|
6083
|
-
}
|
|
6084
|
-
});
|
|
6085
|
-
return CustomError;
|
|
6086
|
-
}
|
|
6087
|
-
function destroyRequest(request, error) {
|
|
6088
|
-
for (var event of events) {
|
|
6089
|
-
request.removeListener(event, eventHandlers[event]);
|
|
5094
|
+
getRemaining() {
|
|
5095
|
+
if (this.maxBudget === null) return null;
|
|
5096
|
+
return Math.max(0, this.maxBudget - this.totalCost);
|
|
6090
5097
|
}
|
|
6091
|
-
|
|
6092
|
-
request.destroy(error);
|
|
6093
|
-
}
|
|
6094
|
-
function isSubdomain(subdomain, domain) {
|
|
6095
|
-
assert(isString(subdomain) && isString(domain));
|
|
6096
|
-
var dot = subdomain.length - domain.length - 1;
|
|
6097
|
-
return dot > 0 && subdomain[dot] === "." && subdomain.endsWith(domain);
|
|
6098
|
-
}
|
|
6099
|
-
function isArray(value) {
|
|
6100
|
-
return value instanceof Array;
|
|
6101
|
-
}
|
|
6102
|
-
function isString(value) {
|
|
6103
|
-
return typeof value === "string" || value instanceof String;
|
|
6104
|
-
}
|
|
6105
|
-
function isFunction(value) {
|
|
6106
|
-
return typeof value === "function";
|
|
6107
|
-
}
|
|
6108
|
-
function isBuffer(value) {
|
|
6109
|
-
return typeof value === "object" && "length" in value;
|
|
6110
|
-
}
|
|
6111
|
-
function isURL(value) {
|
|
6112
|
-
return URL2 && value instanceof URL2;
|
|
6113
|
-
}
|
|
6114
|
-
function escapeRegex(regex) {
|
|
6115
|
-
return regex.replace(/[\]\\/()*+?.$]/g, "\\$&");
|
|
6116
|
-
}
|
|
6117
|
-
module.exports = wrap({ http, https });
|
|
6118
|
-
module.exports.wrap = wrap;
|
|
5098
|
+
};
|
|
6119
5099
|
}
|
|
6120
5100
|
});
|
|
6121
5101
|
|
|
@@ -7244,7 +6224,7 @@ var require_streamx = __commonJS({
|
|
|
7244
6224
|
}
|
|
7245
6225
|
}
|
|
7246
6226
|
};
|
|
7247
|
-
var
|
|
6227
|
+
var Readable2 = class _Readable extends Stream {
|
|
7248
6228
|
constructor(opts) {
|
|
7249
6229
|
super(opts);
|
|
7250
6230
|
this._duplexState |= OPENING | WRITE_DONE | READ_READ_AHEAD;
|
|
@@ -7261,7 +6241,7 @@ var require_streamx = __commonJS({
|
|
|
7261
6241
|
fn().then((src) => {
|
|
7262
6242
|
if (src === null) return out.end();
|
|
7263
6243
|
if (out.destroying) return;
|
|
7264
|
-
|
|
6244
|
+
pipeline2(src, out, noop);
|
|
7265
6245
|
}).catch((err) => out.destroy(err));
|
|
7266
6246
|
return out;
|
|
7267
6247
|
}
|
|
@@ -7455,7 +6435,7 @@ var require_streamx = __commonJS({
|
|
|
7455
6435
|
return this;
|
|
7456
6436
|
}
|
|
7457
6437
|
};
|
|
7458
|
-
var Duplex = class extends
|
|
6438
|
+
var Duplex = class extends Readable2 {
|
|
7459
6439
|
// and Writable
|
|
7460
6440
|
constructor(opts) {
|
|
7461
6441
|
super(opts);
|
|
@@ -7548,13 +6528,13 @@ var require_streamx = __commonJS({
|
|
|
7548
6528
|
}
|
|
7549
6529
|
function pipelinePromise(...streams) {
|
|
7550
6530
|
return new Promise((resolve3, reject) => {
|
|
7551
|
-
return
|
|
6531
|
+
return pipeline2(...streams, (err) => {
|
|
7552
6532
|
if (err) return reject(err);
|
|
7553
6533
|
resolve3();
|
|
7554
6534
|
});
|
|
7555
6535
|
});
|
|
7556
6536
|
}
|
|
7557
|
-
function
|
|
6537
|
+
function pipeline2(stream, ...streams) {
|
|
7558
6538
|
const all = Array.isArray(stream) ? [...stream, ...streams] : [stream, ...streams];
|
|
7559
6539
|
const done = all.length && typeof all[all.length - 1] === "function" ? all.pop() : null;
|
|
7560
6540
|
if (all.length < 2) throw StreamError.BAD_ARGUMENT("Pipeline requires at least 2 streams");
|
|
@@ -7652,7 +6632,7 @@ var require_streamx = __commonJS({
|
|
|
7652
6632
|
return s._writev !== Writable.prototype._writev && s._writev !== Duplex.prototype._writev;
|
|
7653
6633
|
}
|
|
7654
6634
|
module.exports = {
|
|
7655
|
-
pipeline,
|
|
6635
|
+
pipeline: pipeline2,
|
|
7656
6636
|
pipelinePromise,
|
|
7657
6637
|
isStream,
|
|
7658
6638
|
isStreamx,
|
|
@@ -7664,7 +6644,7 @@ var require_streamx = __commonJS({
|
|
|
7664
6644
|
getStreamError,
|
|
7665
6645
|
Stream,
|
|
7666
6646
|
Writable,
|
|
7667
|
-
Readable,
|
|
6647
|
+
Readable: Readable2,
|
|
7668
6648
|
Duplex,
|
|
7669
6649
|
Transform,
|
|
7670
6650
|
// Export PassThrough for compatibility with Node.js core's stream module
|
|
@@ -7673,9 +6653,9 @@ var require_streamx = __commonJS({
|
|
|
7673
6653
|
}
|
|
7674
6654
|
});
|
|
7675
6655
|
|
|
7676
|
-
// ../../node_modules/
|
|
6656
|
+
// ../../node_modules/@sparticuz/chromium/node_modules/tar-stream/headers.js
|
|
7677
6657
|
var require_headers = __commonJS({
|
|
7678
|
-
"../../node_modules/
|
|
6658
|
+
"../../node_modules/@sparticuz/chromium/node_modules/tar-stream/headers.js"(exports) {
|
|
7679
6659
|
var b4a = require_b4a();
|
|
7680
6660
|
var ZEROS = "0000000000000000000";
|
|
7681
6661
|
var SEVENS = "7777777777777777777";
|
|
@@ -7933,10 +6913,10 @@ var require_headers = __commonJS({
|
|
|
7933
6913
|
}
|
|
7934
6914
|
});
|
|
7935
6915
|
|
|
7936
|
-
// ../../node_modules/
|
|
6916
|
+
// ../../node_modules/@sparticuz/chromium/node_modules/tar-stream/extract.js
|
|
7937
6917
|
var require_extract = __commonJS({
|
|
7938
|
-
"../../node_modules/
|
|
7939
|
-
var { Writable, Readable, getStreamError } = require_streamx();
|
|
6918
|
+
"../../node_modules/@sparticuz/chromium/node_modules/tar-stream/extract.js"(exports, module) {
|
|
6919
|
+
var { Writable, Readable: Readable2, getStreamError } = require_streamx();
|
|
7940
6920
|
var FIFO = require_fast_fifo();
|
|
7941
6921
|
var b4a = require_b4a();
|
|
7942
6922
|
var headers = require_headers();
|
|
@@ -7983,7 +6963,7 @@ var require_extract = __commonJS({
|
|
|
7983
6963
|
return buf.subarray(this._offset, this._offset += size);
|
|
7984
6964
|
}
|
|
7985
6965
|
};
|
|
7986
|
-
var Source = class extends
|
|
6966
|
+
var Source = class extends Readable2 {
|
|
7987
6967
|
constructor(self, header, offset) {
|
|
7988
6968
|
super();
|
|
7989
6969
|
this.header = header;
|
|
@@ -8267,9 +7247,9 @@ var require_extract = __commonJS({
|
|
|
8267
7247
|
}
|
|
8268
7248
|
});
|
|
8269
7249
|
|
|
8270
|
-
// ../../node_modules/
|
|
7250
|
+
// ../../node_modules/@sparticuz/chromium/node_modules/tar-stream/constants.js
|
|
8271
7251
|
var require_constants = __commonJS({
|
|
8272
|
-
"../../node_modules/
|
|
7252
|
+
"../../node_modules/@sparticuz/chromium/node_modules/tar-stream/constants.js"(exports, module) {
|
|
8273
7253
|
var constants = {
|
|
8274
7254
|
// just for envs without fs
|
|
8275
7255
|
S_IFMT: 61440,
|
|
@@ -8287,10 +7267,10 @@ var require_constants = __commonJS({
|
|
|
8287
7267
|
}
|
|
8288
7268
|
});
|
|
8289
7269
|
|
|
8290
|
-
// ../../node_modules/
|
|
7270
|
+
// ../../node_modules/@sparticuz/chromium/node_modules/tar-stream/pack.js
|
|
8291
7271
|
var require_pack = __commonJS({
|
|
8292
|
-
"../../node_modules/
|
|
8293
|
-
var { Readable, Writable, getStreamError } = require_streamx();
|
|
7272
|
+
"../../node_modules/@sparticuz/chromium/node_modules/tar-stream/pack.js"(exports, module) {
|
|
7273
|
+
var { Readable: Readable2, Writable, getStreamError } = require_streamx();
|
|
8294
7274
|
var b4a = require_b4a();
|
|
8295
7275
|
var constants = require_constants();
|
|
8296
7276
|
var headers = require_headers();
|
|
@@ -8383,7 +7363,7 @@ var require_pack = __commonJS({
|
|
|
8383
7363
|
cb();
|
|
8384
7364
|
}
|
|
8385
7365
|
};
|
|
8386
|
-
var Pack = class extends
|
|
7366
|
+
var Pack = class extends Readable2 {
|
|
8387
7367
|
constructor(opts) {
|
|
8388
7368
|
super(opts);
|
|
8389
7369
|
this._drain = noop;
|
|
@@ -8521,9 +7501,9 @@ var require_pack = __commonJS({
|
|
|
8521
7501
|
}
|
|
8522
7502
|
});
|
|
8523
7503
|
|
|
8524
|
-
// ../../node_modules/
|
|
7504
|
+
// ../../node_modules/@sparticuz/chromium/node_modules/tar-stream/index.js
|
|
8525
7505
|
var require_tar_stream = __commonJS({
|
|
8526
|
-
"../../node_modules/
|
|
7506
|
+
"../../node_modules/@sparticuz/chromium/node_modules/tar-stream/index.js"(exports) {
|
|
8527
7507
|
exports.extract = require_extract();
|
|
8528
7508
|
exports.pack = require_pack();
|
|
8529
7509
|
}
|
|
@@ -8761,9 +7741,9 @@ var require_pump = __commonJS({
|
|
|
8761
7741
|
}
|
|
8762
7742
|
});
|
|
8763
7743
|
|
|
8764
|
-
// ../../node_modules/tar-fs/index.js
|
|
7744
|
+
// ../../node_modules/@sparticuz/chromium/node_modules/tar-fs/index.js
|
|
8765
7745
|
var require_tar_fs = __commonJS({
|
|
8766
|
-
"../../node_modules/tar-fs/index.js"(exports) {
|
|
7746
|
+
"../../node_modules/@sparticuz/chromium/node_modules/tar-fs/index.js"(exports) {
|
|
8767
7747
|
var tar = require_tar_stream();
|
|
8768
7748
|
var pump = require_pump();
|
|
8769
7749
|
var fs2 = __require("fs");
|
|
@@ -9089,10 +8069,9 @@ var require_tar_fs = __commonJS({
|
|
|
9089
8069
|
}
|
|
9090
8070
|
}
|
|
9091
8071
|
});
|
|
9092
|
-
var
|
|
8072
|
+
var import_tar_fs, setupLambdaEnvironment, isValidUrl, isRunningInAmazonLinux2023, downloadAndExtract;
|
|
9093
8073
|
var init_helper = __esm({
|
|
9094
|
-
"../../node_modules/@sparticuz/chromium/build/
|
|
9095
|
-
import_follow_redirects = __toESM(require_follow_redirects());
|
|
8074
|
+
"../../node_modules/@sparticuz/chromium/build/helper.js"() {
|
|
9096
8075
|
import_tar_fs = __toESM(require_tar_fs());
|
|
9097
8076
|
setupLambdaEnvironment = (baseLibPath) => {
|
|
9098
8077
|
process.env["FONTCONFIG_PATH"] ??= join(tmpdir(), "fonts");
|
|
@@ -9108,7 +8087,13 @@ var init_helper = __esm({
|
|
|
9108
8087
|
};
|
|
9109
8088
|
isValidUrl = (input) => {
|
|
9110
8089
|
try {
|
|
9111
|
-
|
|
8090
|
+
const url = new URL(input);
|
|
8091
|
+
if (url.protocol === "https:")
|
|
8092
|
+
return true;
|
|
8093
|
+
if (url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "[::1]")) {
|
|
8094
|
+
return true;
|
|
8095
|
+
}
|
|
8096
|
+
return false;
|
|
9112
8097
|
} catch {
|
|
9113
8098
|
return false;
|
|
9114
8099
|
}
|
|
@@ -9126,43 +8111,41 @@ var init_helper = __esm({
|
|
|
9126
8111
|
return false;
|
|
9127
8112
|
};
|
|
9128
8113
|
downloadAndExtract = async (url) => {
|
|
9129
|
-
const getOptions = new URL(url);
|
|
9130
|
-
getOptions.maxBodyLength = 60 * 1024 * 1024;
|
|
9131
8114
|
const destDir = join(tmpdir(), "chromium-pack");
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
8115
|
+
const response = await fetch(url, {
|
|
8116
|
+
redirect: "follow",
|
|
8117
|
+
signal: AbortSignal.timeout(3e5)
|
|
8118
|
+
});
|
|
8119
|
+
if (!response.ok) {
|
|
8120
|
+
throw new Error(`Unexpected status code: ${String(response.status)}.`);
|
|
8121
|
+
}
|
|
8122
|
+
if (!response.body) {
|
|
8123
|
+
throw new Error("Response body is empty.");
|
|
8124
|
+
}
|
|
8125
|
+
try {
|
|
8126
|
+
await pipeline(Readable.fromWeb(response.body), (0, import_tar_fs.extract)(destDir));
|
|
8127
|
+
} catch (error) {
|
|
8128
|
+
await new Promise((resolve3) => {
|
|
9135
8129
|
rm(destDir, { force: true, recursive: true }, () => {
|
|
9136
|
-
|
|
8130
|
+
resolve3();
|
|
9137
8131
|
});
|
|
9138
|
-
};
|
|
9139
|
-
extractObj.once("error", cleanupOnError);
|
|
9140
|
-
extractObj.once("finish", () => {
|
|
9141
|
-
resolve3(destDir);
|
|
9142
|
-
});
|
|
9143
|
-
const req = import_follow_redirects.default.https.get(url, (response) => {
|
|
9144
|
-
if (response.statusCode !== 200) {
|
|
9145
|
-
reject(new Error(`Unexpected status code: ${response.statusCode?.toFixed(0) ?? "UNK"}.`));
|
|
9146
|
-
return;
|
|
9147
|
-
}
|
|
9148
|
-
response.pipe(extractObj);
|
|
9149
|
-
response.once("error", cleanupOnError);
|
|
9150
|
-
});
|
|
9151
|
-
req.once("error", cleanupOnError);
|
|
9152
|
-
req.setTimeout(60 * 1e3, () => {
|
|
9153
|
-
req.destroy();
|
|
9154
|
-
cleanupOnError(new Error("Request timeout"));
|
|
9155
8132
|
});
|
|
9156
|
-
|
|
8133
|
+
throw error;
|
|
8134
|
+
}
|
|
8135
|
+
return destDir;
|
|
9157
8136
|
};
|
|
9158
8137
|
}
|
|
9159
8138
|
});
|
|
9160
|
-
var import_tar_fs2, inflate;
|
|
8139
|
+
var import_tar_fs2, ARCHIVE_EXTENSION_REGEX, TAR_EXTENSION_REGEX, BROTLI_EXTENSION_REGEX, GZIP_EXTENSION_REGEX, inflate;
|
|
9161
8140
|
var init_lambdafs = __esm({
|
|
9162
|
-
"../../node_modules/@sparticuz/chromium/build/
|
|
8141
|
+
"../../node_modules/@sparticuz/chromium/build/lambdafs.js"() {
|
|
9163
8142
|
import_tar_fs2 = __toESM(require_tar_fs());
|
|
8143
|
+
ARCHIVE_EXTENSION_REGEX = /\.(?:t(?:ar(?:\.(?:br|gz))?|br|gz)|br|gz)$/i;
|
|
8144
|
+
TAR_EXTENSION_REGEX = /\.t(?:ar(?:\.(?:br|gz))?|br|gz)$/i;
|
|
8145
|
+
BROTLI_EXTENSION_REGEX = /br$/i;
|
|
8146
|
+
GZIP_EXTENSION_REGEX = /gz$/i;
|
|
9164
8147
|
inflate = (filePath) => {
|
|
9165
|
-
const output = filePath.includes("swiftshader") ? tmpdir() : join(tmpdir(), basename(filePath).replace(
|
|
8148
|
+
const output = filePath.includes("swiftshader") ? tmpdir() : join(tmpdir(), basename(filePath).replace(ARCHIVE_EXTENSION_REGEX, ""));
|
|
9166
8149
|
return new Promise((resolve3, reject) => {
|
|
9167
8150
|
if (filePath.includes("swiftshader")) {
|
|
9168
8151
|
if (existsSync(`${output}/libGLESv2.so`)) {
|
|
@@ -9173,9 +8156,9 @@ var init_lambdafs = __esm({
|
|
|
9173
8156
|
resolve3(output);
|
|
9174
8157
|
return;
|
|
9175
8158
|
}
|
|
9176
|
-
const isBrotli =
|
|
9177
|
-
const isGzip =
|
|
9178
|
-
const isTar =
|
|
8159
|
+
const isBrotli = BROTLI_EXTENSION_REGEX.test(filePath);
|
|
8160
|
+
const isGzip = GZIP_EXTENSION_REGEX.test(filePath);
|
|
8161
|
+
const isTar = TAR_EXTENSION_REGEX.test(filePath);
|
|
9179
8162
|
const highWaterMark = 2 ** 22;
|
|
9180
8163
|
const source = createReadStream(filePath, { highWaterMark });
|
|
9181
8164
|
let target;
|
|
@@ -9207,24 +8190,28 @@ var init_lambdafs = __esm({
|
|
|
9207
8190
|
}
|
|
9208
8191
|
});
|
|
9209
8192
|
function getBinPath() {
|
|
9210
|
-
return join(dirname(fileURLToPath(import.meta.url)), "..", "
|
|
8193
|
+
return join(dirname(fileURLToPath(import.meta.url)), "..", "bin");
|
|
9211
8194
|
}
|
|
9212
|
-
var
|
|
9213
|
-
"../../node_modules/@sparticuz/chromium/build/
|
|
8195
|
+
var init_paths = __esm({
|
|
8196
|
+
"../../node_modules/@sparticuz/chromium/build/paths.js"() {
|
|
9214
8197
|
}
|
|
9215
8198
|
});
|
|
9216
8199
|
|
|
9217
|
-
// ../../node_modules/@sparticuz/chromium/build/
|
|
9218
|
-
var
|
|
9219
|
-
__export(
|
|
9220
|
-
default: () =>
|
|
8200
|
+
// ../../node_modules/@sparticuz/chromium/build/index.js
|
|
8201
|
+
var build_exports = {};
|
|
8202
|
+
__export(build_exports, {
|
|
8203
|
+
default: () => build_default,
|
|
8204
|
+
inflate: () => inflate,
|
|
8205
|
+
setupLambdaEnvironment: () => setupLambdaEnvironment
|
|
9221
8206
|
});
|
|
9222
|
-
var nodeMajorVersion, Chromium,
|
|
9223
|
-
var
|
|
9224
|
-
"../../node_modules/@sparticuz/chromium/build/
|
|
8207
|
+
var nodeMajorVersion, Chromium, build_default;
|
|
8208
|
+
var init_build = __esm({
|
|
8209
|
+
"../../node_modules/@sparticuz/chromium/build/index.js"() {
|
|
8210
|
+
init_helper();
|
|
8211
|
+
init_lambdafs();
|
|
8212
|
+
init_paths();
|
|
9225
8213
|
init_helper();
|
|
9226
8214
|
init_lambdafs();
|
|
9227
|
-
init_paths_esm();
|
|
9228
8215
|
nodeMajorVersion = Number.parseInt(process.versions.node.split(".")[0] ?? "");
|
|
9229
8216
|
if (isRunningInAmazonLinux2023(nodeMajorVersion)) {
|
|
9230
8217
|
setupLambdaEnvironment(join(tmpdir(), "al2023", "lib"));
|
|
@@ -9343,7 +8330,7 @@ var init_esm = __esm({
|
|
|
9343
8330
|
}
|
|
9344
8331
|
input ??= getBinPath();
|
|
9345
8332
|
if (!existsSync(input)) {
|
|
9346
|
-
throw new Error(`The input directory "${input}" does not exist.
|
|
8333
|
+
throw new Error(`The input directory "${input}" does not exist. If you are using a bundler (esbuild, webpack, etc.), you must externalize @sparticuz/chromium so it is not relocated. See: https://github.com/Sparticuz/chromium#bundler-configuration`);
|
|
9347
8334
|
}
|
|
9348
8335
|
const promises = [
|
|
9349
8336
|
inflate(join(input, "chromium.br")),
|
|
@@ -9357,7 +8344,7 @@ var init_esm = __esm({
|
|
|
9357
8344
|
return result.shift();
|
|
9358
8345
|
}
|
|
9359
8346
|
};
|
|
9360
|
-
|
|
8347
|
+
build_default = Chromium;
|
|
9361
8348
|
}
|
|
9362
8349
|
});
|
|
9363
8350
|
|
|
@@ -9366,6 +8353,7 @@ var visual_evaluator_exports = {};
|
|
|
9366
8353
|
__export(visual_evaluator_exports, {
|
|
9367
8354
|
buildRenderHTML: () => buildRenderHTML,
|
|
9368
8355
|
bundleForRendering: () => bundleForRendering,
|
|
8356
|
+
callMultimodalLLM: () => callMultimodalLLM,
|
|
9369
8357
|
runVisualEval: () => runVisualEval,
|
|
9370
8358
|
runVisualEvaluation: () => runVisualEvaluation
|
|
9371
8359
|
});
|
|
@@ -9464,7 +8452,7 @@ ${bundledCode}
|
|
|
9464
8452
|
async function captureScreenshot(html, viewport = { width: 1280, height: 800 }) {
|
|
9465
8453
|
try {
|
|
9466
8454
|
const puppeteer = await import('puppeteer-core');
|
|
9467
|
-
const chromium = await Promise.resolve().then(() => (
|
|
8455
|
+
const chromium = await Promise.resolve().then(() => (init_build(), build_exports));
|
|
9468
8456
|
const launchOptions = {
|
|
9469
8457
|
args: chromium.default.args,
|
|
9470
8458
|
defaultViewport: viewport,
|
|
@@ -9474,7 +8462,9 @@ async function captureScreenshot(html, viewport = { width: 1280, height: 800 })
|
|
|
9474
8462
|
const browser = await puppeteer.default.launch(launchOptions);
|
|
9475
8463
|
try {
|
|
9476
8464
|
const page = await browser.newPage();
|
|
9477
|
-
await page.setContent(html, { waitUntil: "
|
|
8465
|
+
await page.setContent(html, { waitUntil: "load", timeout: 15e3 });
|
|
8466
|
+
await page.waitForNetworkIdle({ idleTime: 500, timeout: 15e3 }).catch(() => {
|
|
8467
|
+
});
|
|
9478
8468
|
await page.waitForSelector("#root > *", { timeout: 1e4 }).catch(() => {
|
|
9479
8469
|
});
|
|
9480
8470
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
@@ -9488,63 +8478,23 @@ async function captureScreenshot(html, viewport = { width: 1280, height: 800 })
|
|
|
9488
8478
|
return null;
|
|
9489
8479
|
}
|
|
9490
8480
|
}
|
|
9491
|
-
async function callMultimodalLLM(
|
|
8481
|
+
async function callMultimodalLLM(config, model, prompt, screenshot, originalPrompt) {
|
|
9492
8482
|
const userPrompt = `## Original Request
|
|
9493
8483
|
${originalPrompt}
|
|
9494
8484
|
|
|
9495
8485
|
Evaluate the screenshot of the generated component.`;
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
baseURL: "https://api.anthropic.com"
|
|
9501
|
-
});
|
|
9502
|
-
const response2 = await client2.messages.create({
|
|
9503
|
-
model: model.startsWith("anthropic/") ? model.slice(10) : model,
|
|
9504
|
-
max_tokens: 1500,
|
|
9505
|
-
system: prompt,
|
|
9506
|
-
messages: [{
|
|
9507
|
-
role: "user",
|
|
9508
|
-
content: [
|
|
9509
|
-
{
|
|
9510
|
-
type: "image",
|
|
9511
|
-
source: {
|
|
9512
|
-
type: "base64",
|
|
9513
|
-
media_type: "image/png",
|
|
9514
|
-
data: screenshot.toString("base64")
|
|
9515
|
-
}
|
|
9516
|
-
},
|
|
9517
|
-
{ type: "text", text: userPrompt }
|
|
9518
|
-
]
|
|
9519
|
-
}]
|
|
9520
|
-
});
|
|
9521
|
-
return {
|
|
9522
|
-
text: response2.content.filter((b) => b.type === "text").map((b) => b.text).join(""),
|
|
9523
|
-
inputTokens: response2.usage.input_tokens,
|
|
9524
|
-
outputTokens: response2.usage.output_tokens
|
|
9525
|
-
};
|
|
9526
|
-
}
|
|
9527
|
-
const { GoogleGenAI } = await import('@google/genai');
|
|
9528
|
-
const client = new GoogleGenAI({
|
|
9529
|
-
apiKey: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
|
9530
|
-
});
|
|
9531
|
-
const response = await client.models.generateContent({
|
|
9532
|
-
model: model.startsWith("google/") ? model.slice(7) : model,
|
|
9533
|
-
contents: [{
|
|
9534
|
-
role: "user",
|
|
9535
|
-
parts: [
|
|
9536
|
-
{ inlineData: { mimeType: "image/png", data: screenshot.toString("base64") } },
|
|
9537
|
-
{ text: userPrompt }
|
|
9538
|
-
]
|
|
9539
|
-
}],
|
|
9540
|
-
config: { systemInstruction: prompt }
|
|
8486
|
+
const agent = createVisionAgent({
|
|
8487
|
+
provider: config.provider === "claude" ? "anthropic" : config.provider,
|
|
8488
|
+
routeOverride: config.routeOverride,
|
|
8489
|
+
onRetry: config.onRetry
|
|
9541
8490
|
});
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
|
|
8491
|
+
return agent.callVision(
|
|
8492
|
+
model,
|
|
8493
|
+
prompt,
|
|
8494
|
+
userPrompt,
|
|
8495
|
+
{ mediaType: "image/png", base64: screenshot.toString("base64") },
|
|
8496
|
+
1500
|
|
8497
|
+
);
|
|
9548
8498
|
}
|
|
9549
8499
|
async function runVisualEvaluation(context, config) {
|
|
9550
8500
|
const startTime = Date.now();
|
|
@@ -9562,7 +8512,7 @@ async function runVisualEvaluation(context, config) {
|
|
|
9562
8512
|
console.log(`[visual-eval] screenshot: ${screenshot.length}B (${Date.now() - startTime}ms)`);
|
|
9563
8513
|
const model = config.model ?? getDefaultVisualModel(config.provider);
|
|
9564
8514
|
const response = await callMultimodalLLM(
|
|
9565
|
-
config
|
|
8515
|
+
config,
|
|
9566
8516
|
model,
|
|
9567
8517
|
VISUAL_EVAL_PROMPT,
|
|
9568
8518
|
screenshot,
|
|
@@ -9636,6 +8586,7 @@ async function runVisualEval(context, config) {
|
|
|
9636
8586
|
var VISUAL_EVAL_PROMPT;
|
|
9637
8587
|
var init_visual_evaluator = __esm({
|
|
9638
8588
|
"src/evaluation/visual-evaluator.ts"() {
|
|
8589
|
+
init_llm_router();
|
|
9639
8590
|
VISUAL_EVAL_PROMPT = `You are a visual quality evaluator for ggui \u2014 a platform where AI agents generate React UI components on demand.
|
|
9640
8591
|
|
|
9641
8592
|
## Context
|
|
@@ -10873,11 +9824,11 @@ var stateFragments = {
|
|
|
10873
9824
|
axis: "state",
|
|
10874
9825
|
value: "merge",
|
|
10875
9826
|
cacheTier: "axisDelta",
|
|
10876
|
-
promptText: "## State: merge (live entity reconciliation)\n1. Seed `const [items, setItems] = useState(props.items ?? [])
|
|
9827
|
+
promptText: "## State: merge (live entity reconciliation)\n1. Seed `const [items, setItems] = useState(props.items ?? [])` AND re-seed on prop change: `useEffect(() => setItems(props.items ?? []), [props.items])` \u2014 a `ggui_amend` repaint must move the list.\n2. On stream updates: `setItems(prev => prev.map(it => it.id === event.id ? { ...it, ...event } : it))` \u2014 merge by id, do NOT append.\n3. Memoize derived views (grouping/sorting/filtering) with useMemo.\n4. Per-item actions pass `{ id, ... }` in the payload.\n5. Never push the stream payload into an append-only list unless realtime=append.",
|
|
10877
9828
|
boilerplateMarker: [
|
|
10878
9829
|
"",
|
|
10879
9830
|
" // \u2500\u2500 Live entity state (merge-by-id) \u2500\u2500",
|
|
10880
|
-
" // useState(props.items ?? []); merge stream events by item.id; never append.",
|
|
9831
|
+
" // useState(props.items ?? []); re-seed via useEffect on [props.items]; merge stream events by item.id; never append.",
|
|
10881
9832
|
""
|
|
10882
9833
|
].join("\n")
|
|
10883
9834
|
},
|
|
@@ -10995,13 +9946,13 @@ var realtimeFragments = {
|
|
|
10995
9946
|
axis: "realtime",
|
|
10996
9947
|
value: "merge",
|
|
10997
9948
|
cacheTier: "axisDelta",
|
|
10998
|
-
promptText: "## Realtime: merge\nStream events carry an id; merge into LOCAL STATE. Subscribing alone is not enough \u2014 the local list must update on each event for the DOM to re-render.\n\n```tsx\nconst stream = useStream<UpdateT>('streamName');\nconst [items, setItems] = useState(props.items);\nuseEffect(() => {\n if (!stream.latest) return;\n setItems((prev) => prev.map((it) => it.id === stream.latest!.id ? { ...it, ...stream.latest } : it));\n}, [stream.latest]);\n// Render `items.map(...)` \u2014 NOT props.items, NOT stream.all.\n```\n\nNever append \u2014 stream=merge means the entity already exists locally."
|
|
9949
|
+
promptText: "## Realtime: merge\nStream events carry an id; merge into LOCAL STATE. Subscribing alone is not enough \u2014 the local list must update on each event for the DOM to re-render.\n\n```tsx\nconst stream = useStream<UpdateT>('streamName');\nconst [items, setItems] = useState(props.items);\nuseEffect(() => setItems(props.items), [props.items]); // re-seed on ggui_amend repaint \u2014 props stay the source of truth\nuseEffect(() => {\n if (!stream.latest) return;\n setItems((prev) => prev.map((it) => it.id === stream.latest!.id ? { ...it, ...stream.latest } : it));\n}, [stream.latest]);\n// Render `items.map(...)` \u2014 NOT props.items, NOT stream.all.\n```\n\nNever append \u2014 stream=merge means the entity already exists locally."
|
|
10999
9950
|
},
|
|
11000
9951
|
append: {
|
|
11001
9952
|
axis: "realtime",
|
|
11002
9953
|
value: "append",
|
|
11003
9954
|
cacheTier: "axisDelta",
|
|
11004
|
-
promptText: "## Realtime: append\nStream events are new entities; APPEND to local state. Subscribing alone is not enough \u2014 the local list must update for the DOM to re-render.\n\n```tsx\nconst stream = useStream<EventT>('streamName');\nconst [items, setItems] = useState(props.items);\nuseEffect(() => {\n if (!stream.latest) return;\n setItems((prev) => [...prev, stream.latest!]);\n}, [stream.latest]);\n// Render `items.map(...)` \u2014 NOT props.items, NOT stream.all (which accumulates only post-mount).\n```\n\nUse head for newest-first, tail for chat-style. Cap list length if needed. Do not dedupe unless the contract guarantees at-most-once."
|
|
9955
|
+
promptText: "## Realtime: append\nStream events are new entities; APPEND to local state. Subscribing alone is not enough \u2014 the local list must update for the DOM to re-render.\n\n```tsx\nconst stream = useStream<EventT>('streamName');\nconst [items, setItems] = useState(props.items);\nuseEffect(() => setItems(props.items), [props.items]); // re-seed on ggui_amend repaint \u2014 props stay the source of truth\nuseEffect(() => {\n if (!stream.latest) return;\n setItems((prev) => [...prev, stream.latest!]);\n}, [stream.latest]);\n// Render `items.map(...)` \u2014 NOT props.items, NOT stream.all (which accumulates only post-mount).\n```\n\nUse head for newest-first, tail for chat-style. Cap list length if needed. Do not dedupe unless the contract guarantees at-most-once."
|
|
11005
9956
|
},
|
|
11006
9957
|
status: {
|
|
11007
9958
|
axis: "realtime",
|
|
@@ -11019,7 +9970,7 @@ var realtimeFragments = {
|
|
|
11019
9970
|
axis: "realtime",
|
|
11020
9971
|
value: "mixed",
|
|
11021
9972
|
cacheTier: "axisDelta",
|
|
11022
|
-
promptText: "## Realtime: mixed\nMultiple stream channels with DIFFERENT semantics. Each `streamKinds` entry in the contract maps to one of: merge, append, status, presence. Subscribe + sync to local state PER CHANNEL \u2014 subscribing alone never re-renders the DOM.\n\nExample (chat-interface \u2014 message=append, typing=presence):\n\n```tsx\nconst messages = useStream<MessageT>('message');\nconst typing = useStream<TypingT>('typing');\nconst [messageList, setMessageList] = useState(props.messages);\nconst [typingUsers, setTypingUsers] = useState<Set<string>>(new Set());\n\nuseEffect(() => {\n if (!messages.latest) return;\n setMessageList((prev) => [...prev, messages.latest!]);\n}, [messages.latest]);\n\nuseEffect(() => {\n if (!typing.latest) return;\n setTypingUsers((prev) => {\n const next = new Set(prev);\n if (typing.latest!.active) next.add(typing.latest!.sender);\n else next.delete(typing.latest!.sender);\n return next;\n });\n}, [typing.latest]);\n```\n\nDo NOT treat all events the same. Do NOT skip the local-state sync \u2014 `useStream` alone won't trigger DOM updates of your derived view.",
|
|
9973
|
+
promptText: "## Realtime: mixed\nMultiple stream channels with DIFFERENT semantics. Each `streamKinds` entry in the contract maps to one of: merge, append, status, presence. Subscribe + sync to local state PER CHANNEL \u2014 subscribing alone never re-renders the DOM.\n\nExample (chat-interface \u2014 message=append, typing=presence):\n\n```tsx\nconst messages = useStream<MessageT>('message');\nconst typing = useStream<TypingT>('typing');\nconst [messageList, setMessageList] = useState(props.messages);\nconst [typingUsers, setTypingUsers] = useState<Set<string>>(new Set());\n\nuseEffect(() => setMessageList(props.messages), [props.messages]); // re-seed on ggui_amend repaint\n\nuseEffect(() => {\n if (!messages.latest) return;\n setMessageList((prev) => [...prev, messages.latest!]);\n}, [messages.latest]);\n\nuseEffect(() => {\n if (!typing.latest) return;\n setTypingUsers((prev) => {\n const next = new Set(prev);\n if (typing.latest!.active) next.add(typing.latest!.sender);\n else next.delete(typing.latest!.sender);\n return next;\n });\n}, [typing.latest]);\n```\n\nDo NOT treat all events the same. Do NOT skip the local-state sync \u2014 `useStream` alone won't trigger DOM updates of your derived view.",
|
|
11023
9974
|
boilerplateMarker: [
|
|
11024
9975
|
"",
|
|
11025
9976
|
" // \u2500\u2500 Mixed stream handlers \u2500\u2500",
|
|
@@ -11330,13 +10281,14 @@ function generateBoilerplate(_userPrompt, contract, shellType, screen, composedS
|
|
|
11330
10281
|
const propsFields = [];
|
|
11331
10282
|
const propsProperties = contract?.propsSpec?.properties ?? {};
|
|
11332
10283
|
for (const [key, entry] of Object.entries(propsProperties)) {
|
|
11333
|
-
const required = entry.required
|
|
10284
|
+
const required = entry.required === true;
|
|
11334
10285
|
const nullable = entry.schema.nullable === true;
|
|
11335
10286
|
const tsType = jsonSchemaTypeToTs(entry.schema);
|
|
11336
10287
|
const fullType = nullable ? `${tsType} | null` : tsType;
|
|
11337
10288
|
const parts = [];
|
|
11338
10289
|
if (entry.description) parts.push(entry.description);
|
|
11339
10290
|
if (entry.default !== void 0) parts.push(`(default: ${JSON.stringify(entry.default)})`);
|
|
10291
|
+
if (!required) parts.push("(optional \u2014 the agent may omit it; guard or fall back)");
|
|
11340
10292
|
const desc = parts.length > 0 ? ` // ${parts.join(" ")}` : "";
|
|
11341
10293
|
propsFields.push(` ${key}${required ? "" : "?"}: ${fullType};${desc}`);
|
|
11342
10294
|
}
|
|
@@ -11893,13 +10845,15 @@ A \`DataContract\` declares everything a GguiSession exchanges with the outside
|
|
|
11893
10845
|
|
|
11894
10846
|
## Defensive coding for absent / late-arriving data
|
|
11895
10847
|
|
|
11896
|
-
Props arrive
|
|
10848
|
+
Props arrive at mount and may be partial on first render; later prop changes reach the SAME mounted component via \`ggui_amend\` (in-place repaint) on the live channel. Stream channels start empty and fill over time. Context slots start at their declared default (often \`null\`). **Never assume a field exists before you read it.**
|
|
11897
10849
|
|
|
10850
|
+
- **Optional contract props**: a \`Props\` field marked \`?\` in the boilerplate may be omitted by the agent ENTIRELY \u2014 the wire gate only enforces \`required: true\` entries, and the harness verifies your component with those props stripped. Guard them (\`?? default\`, \`?.\`, or an empty-state branch) from the FIRST render.
|
|
11898
10851
|
- **Array iteration**: always default to \`[]\` before \`.map\`/\`.filter\`/\`.length\`. Use \`(props.items ?? []).map(...)\` not \`props.items.map(...)\`. Same for stream.all, stream.latest, etc.
|
|
11899
10852
|
- **Object access**: optional-chain through nested fields. \`props.user?.name ?? 'Anonymous'\` not \`props.user.name\`.
|
|
11900
10853
|
- **Number ops**: default before arithmetic. \`(props.count ?? 0) + 1\` not \`props.count + 1\`.
|
|
11901
10854
|
- **Stream latest**: \`useStream\` returns \`{latest: T | null, all: T[], isComplete: boolean}\`. The default \`all\` is \`[]\` so it's safe to map; \`latest\` is null until the first frame arrives \u2014 guard before reading \`.foo\`.
|
|
11902
10855
|
- **Stream reconciliation**: when a stream event carries an \`action\` discriminant (e.g. \`create | move | edit | delete\`), the channel is a CRUD feed \u2014 your handler MUST branch on EVERY value: append on \`create\`, drop on \`delete\`, replace-by-id on \`move\` / \`edit\`. Merging only the "edit" case silently loses created and deleted items. Reconcile into the SAME state that seeds from \`props\` (e.g. \`useState(() => props.tasks ?? [])\`) so the seed data and the live feed render as one list \u2014 and handle an event whose id is not yet present (a \`create\` for an unknown item) by inserting it, not ignoring it.
|
|
10856
|
+
- **Props re-sync on repaint**: props the agent owns are the source of truth for display \u2014 prefer rendering DIRECTLY from \`props\` (controlled, no local copy). When local optimistic state genuinely needs a prop seed (a click bumps a count before the agent confirms), it MUST re-sync on prop change \u2014 \`useEffect(() => setCount(props.count ?? 0), [props.count])\` \u2014 or a \`ggui_amend\` repaint applies the new props while the display keeps the stale local value. BAD: \`const [count, setCount] = useState(props.count ?? 0)\` alone. GOOD: the same seed + the one-line re-sync effect.
|
|
11903
10857
|
- **Loading state**: while data is still absent, render \`<Skeleton>\` placeholders \u2014 never a blank screen. \`<Skeleton variant="text" />\` for a text line, \`variant="circle"\` for an avatar slot, default \`rect\` for a block.
|
|
11904
10858
|
- **Empty state**: when a list or results array is empty, render \`<EmptyState title="\u2026" description="\u2026" />\` \u2014 a region that renders nothing when empty looks broken to the user.
|
|
11905
10859
|
|
|
@@ -12027,7 +10981,7 @@ Every value change is mirrored to the host LLM's context automatically (debounce
|
|
|
12027
10981
|
|
|
12028
10982
|
**When NOT to use it.** Local UI state the contract did NOT declare \u2014 \`isDropdownOpen\`, hover flags, animation phase, ephemeral toggles. For those, use a plain \`useState\` directly. The runtime ignores undeclared state.
|
|
12029
10983
|
|
|
12030
|
-
**\`contextSpec\` direction is one-way: client \u2192 agent.** The agent uses \`propsSpec\` (via \`ggui_update\`) and \`streamSpec\` (via the live channel) to push state TO the client. Don't try to write to the agent via \`contextSpec\` \u2014 there is no return path.
|
|
10984
|
+
**\`contextSpec\` direction is one-way: client \u2192 agent.** The agent uses \`propsSpec\` (via \`ggui_amend\` for in-place repaints of this mount, or \`ggui_update\` when it mints a new history card) and \`streamSpec\` (via the live channel) to push state TO the client. Don't try to write to the agent via \`contextSpec\` \u2014 there is no return path.
|
|
12031
10985
|
|
|
12032
10986
|
**Schema mismatches drop silently.** If you set a value that doesn't match the slot's schema (e.g. a string into a \`{type: 'number'}\` slot), the runtime logs a dev \`console.warn\` and skips the post. Make sure your setter calls produce values that match the declared shape.
|
|
12033
10987
|
|
|
@@ -12835,10 +11789,12 @@ These tokens adapt automatically to any theme (light, dark, branded). **ALWAYS u
|
|
|
12835
11789
|
- Borders/dividers \u2192 \`var(--ggui-color-outline)\` or \`var(--ggui-color-outlineVariant)\`
|
|
12836
11790
|
|
|
12837
11791
|
### State Colors
|
|
12838
|
-
|
|
12839
|
-
- var(--ggui-color-
|
|
12840
|
-
- var(--ggui-color-
|
|
12841
|
-
- var(--ggui-color-
|
|
11792
|
+
Semantic families ship as SCALES; the \`500\` stop is the role color (per-mode brightness), \`50\` the tint, \`800\` the on-tint text:
|
|
11793
|
+
- var(--ggui-color-success-500) \u2014 success states (tint bg: success-50, text on tint: success-800)
|
|
11794
|
+
- var(--ggui-color-warning-500) \u2014 warning states (warning-50 / warning-800)
|
|
11795
|
+
- var(--ggui-color-error-500) \u2014 error states, destructive actions (error-50 / error-800)
|
|
11796
|
+
- var(--ggui-color-info-500) \u2014 informational (info-50 / info-800)
|
|
11797
|
+
Prefer the primitives' \`tone="success|warning|error|info"\` prop over hand-written vars \u2014 it resolves to the same stops.
|
|
12842
11798
|
|
|
12843
11799
|
### IMPORTANT: Color Rules
|
|
12844
11800
|
- **NEVER** use hardcoded hex colors. ONLY use var(--ggui-color-*) tokens.
|
|
@@ -13458,6 +12414,31 @@ function runNoPhantomUseState(input) {
|
|
|
13458
12414
|
}
|
|
13459
12415
|
return issues;
|
|
13460
12416
|
}
|
|
12417
|
+
function runPropSeedNoResync(input) {
|
|
12418
|
+
if (input.compiledCode === null) return [];
|
|
12419
|
+
const src = input.sourceCode;
|
|
12420
|
+
const issues = [];
|
|
12421
|
+
const re = /const\s*\[\s*(\w+)\s*,\s*(\w+)\s*\]\s*=\s*useState(?:<[^>]*>)?\s*\(\s*props\??\.(\w+)/g;
|
|
12422
|
+
for (const m of src.matchAll(re)) {
|
|
12423
|
+
const [full, stateVar, setter, propName] = m;
|
|
12424
|
+
const idx = m.index ?? 0;
|
|
12425
|
+
const after = src.slice(idx + full.length);
|
|
12426
|
+
if (!new RegExp(`\\b${setter}\\s*\\(`).test(after)) continue;
|
|
12427
|
+
const resync = new RegExp(
|
|
12428
|
+
`\\[[^\\[\\]]*props\\??\\.${propName}\\b[^\\[\\]]*\\]`
|
|
12429
|
+
);
|
|
12430
|
+
if (resync.test(src)) continue;
|
|
12431
|
+
issues.push(
|
|
12432
|
+
mkIssue(
|
|
12433
|
+
"universal.prop_seed_no_resync",
|
|
12434
|
+
`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).`,
|
|
12435
|
+
`Add \`useEffect(() => ${setter}(props.${propName}), [props.${propName}]);\` so agent repaints re-seed the state, or derive the display directly from props.${propName}.`,
|
|
12436
|
+
"warn"
|
|
12437
|
+
)
|
|
12438
|
+
);
|
|
12439
|
+
}
|
|
12440
|
+
return issues;
|
|
12441
|
+
}
|
|
13461
12442
|
var UNIVERSAL_CHECKS = [
|
|
13462
12443
|
{
|
|
13463
12444
|
id: "universal.prop_coverage",
|
|
@@ -13476,6 +12457,12 @@ var UNIVERSAL_CHECKS = [
|
|
|
13476
12457
|
axis: "render",
|
|
13477
12458
|
values: ALL_RENDER_VALUES,
|
|
13478
12459
|
run: runNoPhantomUseState
|
|
12460
|
+
},
|
|
12461
|
+
{
|
|
12462
|
+
id: "universal.prop_seed_no_resync",
|
|
12463
|
+
axis: "render",
|
|
12464
|
+
values: ALL_RENDER_VALUES,
|
|
12465
|
+
run: runPropSeedNoResync
|
|
13479
12466
|
}
|
|
13480
12467
|
];
|
|
13481
12468
|
|
|
@@ -13495,7 +12482,7 @@ function runStateSeededFromProps(input) {
|
|
|
13495
12482
|
mkIssue(
|
|
13496
12483
|
"state.merge.seeded_from_props",
|
|
13497
12484
|
`Entity collection "${e.name}" is not seeded from props \u2014 no useState initializer reads props.${e.name}.`,
|
|
13498
|
-
`Add \`const [${e.name}, set${cap(e.name)}] = useState(props.${e.name});\` so stream/action updates
|
|
12485
|
+
`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).`
|
|
13499
12486
|
)
|
|
13500
12487
|
);
|
|
13501
12488
|
}
|
|
@@ -13599,6 +12586,106 @@ var STATE_MERGE_CHECKS = [
|
|
|
13599
12586
|
}
|
|
13600
12587
|
];
|
|
13601
12588
|
|
|
12589
|
+
// src/evaluation/axis-checks/checks/state-ui-affordance.ts
|
|
12590
|
+
var STATE_ARIA_OR_ROLE = /aria-(checked|pressed|selected|expanded|current)\s*=|role\s*=/;
|
|
12591
|
+
var STATE_PRIMITIVE_IN_SUBTREE = /<(Checkbox|Toggle|Tabs|Accordion)[\s/>]/;
|
|
12592
|
+
var SEMANTIC_PRIMITIVES = /* @__PURE__ */ new Set(["Button", "Checkbox", "Toggle", "Link", "MenuItem"]);
|
|
12593
|
+
function collectSetters(src) {
|
|
12594
|
+
const setters = /* @__PURE__ */ new Set();
|
|
12595
|
+
for (const m of src.matchAll(/const\s*\[\s*\w+\s*,\s*(set\w+)\s*\]\s*=\s*useState/g)) {
|
|
12596
|
+
setters.add(m[1]);
|
|
12597
|
+
}
|
|
12598
|
+
return setters;
|
|
12599
|
+
}
|
|
12600
|
+
function collectHandlers(src, setters) {
|
|
12601
|
+
const handlers = /* @__PURE__ */ new Set();
|
|
12602
|
+
for (const m of src.matchAll(/const\s+(\w+)\s*=\s*(?:\([^)]*\)|\w+)\s*=>\s*\{?/g)) {
|
|
12603
|
+
const body = src.slice(m.index + m[0].length, m.index + m[0].length + 400);
|
|
12604
|
+
for (const s of setters) {
|
|
12605
|
+
if (body.includes(s)) {
|
|
12606
|
+
handlers.add(m[1]);
|
|
12607
|
+
break;
|
|
12608
|
+
}
|
|
12609
|
+
}
|
|
12610
|
+
}
|
|
12611
|
+
return handlers;
|
|
12612
|
+
}
|
|
12613
|
+
function attrBlock(src, start) {
|
|
12614
|
+
let depth = 0;
|
|
12615
|
+
for (let i = start; i < src.length; i++) {
|
|
12616
|
+
const c = src[i];
|
|
12617
|
+
if (c === "{") depth++;
|
|
12618
|
+
else if (c === "}") depth--;
|
|
12619
|
+
else if (c === ">" && depth === 0) return { block: src.slice(start, i), end: i };
|
|
12620
|
+
}
|
|
12621
|
+
return { block: src.slice(start, start + 900), end: start + 900 };
|
|
12622
|
+
}
|
|
12623
|
+
function onClickValue(block) {
|
|
12624
|
+
const m = block.match(/onClick\s*=\s*\{/);
|
|
12625
|
+
if (!m || m.index === void 0) return null;
|
|
12626
|
+
const open = m.index + m[0].length - 1;
|
|
12627
|
+
let depth = 0;
|
|
12628
|
+
for (let i = open; i < block.length; i++) {
|
|
12629
|
+
if (block[i] === "{") depth++;
|
|
12630
|
+
else if (block[i] === "}") {
|
|
12631
|
+
depth--;
|
|
12632
|
+
if (depth === 0) return block.slice(open + 1, i);
|
|
12633
|
+
}
|
|
12634
|
+
}
|
|
12635
|
+
return block.slice(open + 1);
|
|
12636
|
+
}
|
|
12637
|
+
function subtree(src, pos, tag) {
|
|
12638
|
+
const close = src.indexOf(`</${tag}>`, pos);
|
|
12639
|
+
return src.slice(pos, close === -1 ? pos + 700 : close);
|
|
12640
|
+
}
|
|
12641
|
+
function runStateAriaPresent(input) {
|
|
12642
|
+
if (input.compiledCode === null) return [];
|
|
12643
|
+
const src = input.sourceCode;
|
|
12644
|
+
const setters = collectSetters(src);
|
|
12645
|
+
const handlers = collectHandlers(src, setters);
|
|
12646
|
+
const issues = [];
|
|
12647
|
+
const flaggedLines = /* @__PURE__ */ new Set();
|
|
12648
|
+
const localComponents = /* @__PURE__ */ new Set();
|
|
12649
|
+
for (const m of src.matchAll(/(?:function\s+([A-Z]\w*)\s*\(|const\s+([A-Z]\w*)\s*=)/g)) {
|
|
12650
|
+
localComponents.add(m[1] ?? m[2]);
|
|
12651
|
+
}
|
|
12652
|
+
for (const m of src.matchAll(/<([A-Za-z][A-Za-z0-9]*)\b/g)) {
|
|
12653
|
+
const tag = m[1];
|
|
12654
|
+
if (m.index === void 0) continue;
|
|
12655
|
+
if (localComponents.has(tag)) continue;
|
|
12656
|
+
const { block, end } = attrBlock(src, m.index + m[0].length);
|
|
12657
|
+
const clickValue = onClickValue(block);
|
|
12658
|
+
if (clickValue === null) continue;
|
|
12659
|
+
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
|
|
12660
|
+
// `on[A-Z]…` callback prop and is invoked from onClick — inside a
|
|
12661
|
+
// ui-affordance component that IS the affordance mutation.
|
|
12662
|
+
/\bon[A-Z]\w*\b/.test(clickValue);
|
|
12663
|
+
if (!mutatesAffordance) continue;
|
|
12664
|
+
if (SEMANTIC_PRIMITIVES.has(tag)) continue;
|
|
12665
|
+
if (STATE_ARIA_OR_ROLE.test(block)) continue;
|
|
12666
|
+
if (STATE_PRIMITIVE_IN_SUBTREE.test(subtree(src, end, tag))) continue;
|
|
12667
|
+
const line = src.slice(0, m.index).split("\n").length;
|
|
12668
|
+
if (flaggedLines.has(line)) continue;
|
|
12669
|
+
flaggedLines.add(line);
|
|
12670
|
+
issues.push(
|
|
12671
|
+
mkIssue(
|
|
12672
|
+
"state.ui_affordance.state_aria_present",
|
|
12673
|
+
`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).`,
|
|
12674
|
+
`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.`
|
|
12675
|
+
)
|
|
12676
|
+
);
|
|
12677
|
+
}
|
|
12678
|
+
return issues;
|
|
12679
|
+
}
|
|
12680
|
+
var STATE_UI_AFFORDANCE_CHECKS = [
|
|
12681
|
+
{
|
|
12682
|
+
id: "state.ui_affordance.state_aria_present",
|
|
12683
|
+
axis: "state",
|
|
12684
|
+
values: ["ui-affordance"],
|
|
12685
|
+
run: runStateAriaPresent
|
|
12686
|
+
}
|
|
12687
|
+
];
|
|
12688
|
+
|
|
13602
12689
|
// src/evaluation/axis-checks/checks/realtime.ts
|
|
13603
12690
|
var REALTIME_ACTIVE = ["merge", "append", "status", "presence", "mixed"];
|
|
13604
12691
|
function runStreamHandlerPerEvent(input) {
|
|
@@ -14288,6 +13375,7 @@ var EXTRA_CHECKS = [
|
|
|
14288
13375
|
var REGISTRY = [
|
|
14289
13376
|
...UNIVERSAL_CHECKS,
|
|
14290
13377
|
...STATE_MERGE_CHECKS,
|
|
13378
|
+
...STATE_UI_AFFORDANCE_CHECKS,
|
|
14291
13379
|
...REALTIME_CHECKS,
|
|
14292
13380
|
...WRITES_CHECKS,
|
|
14293
13381
|
...STATE_PAYLOAD_CHECKS,
|
|
@@ -14458,8 +13546,8 @@ ${cjsResult.code}
|
|
|
14458
13546
|
// src/harness/check/runtime-render/load-component.ts
|
|
14459
13547
|
async function loadComponent(input) {
|
|
14460
13548
|
const { sourceCode, moduleResolutions = {} } = input;
|
|
14461
|
-
const { createRequire:
|
|
14462
|
-
const require_ =
|
|
13549
|
+
const { createRequire: createRequire4 } = await import('module');
|
|
13550
|
+
const require_ = createRequire4(import.meta.url);
|
|
14463
13551
|
const sandboxRequire = (id) => {
|
|
14464
13552
|
if (id in moduleResolutions) return moduleResolutions[id];
|
|
14465
13553
|
if (id === "react/jsx-runtime" || id === "react/jsx-dev-runtime") {
|
|
@@ -14715,6 +13803,47 @@ function wrapDetection(kind, jsx, native, custom) {
|
|
|
14715
13803
|
function dedupe(arr) {
|
|
14716
13804
|
return Array.from(new Set(arr));
|
|
14717
13805
|
}
|
|
13806
|
+
var installed = false;
|
|
13807
|
+
function installProductionActShim() {
|
|
13808
|
+
if (installed) return;
|
|
13809
|
+
installed = true;
|
|
13810
|
+
const require_ = createRequire(import.meta.url);
|
|
13811
|
+
let reactCjs;
|
|
13812
|
+
try {
|
|
13813
|
+
reactCjs = require_("react");
|
|
13814
|
+
} catch {
|
|
13815
|
+
return;
|
|
13816
|
+
}
|
|
13817
|
+
if (typeof reactCjs.act === "function") {
|
|
13818
|
+
return;
|
|
13819
|
+
}
|
|
13820
|
+
try {
|
|
13821
|
+
const testUtils = require_("react-dom/test-utils");
|
|
13822
|
+
const reactDom = require_("react-dom");
|
|
13823
|
+
testUtils.act = createFlushSyncAct(reactDom.flushSync);
|
|
13824
|
+
} catch {
|
|
13825
|
+
}
|
|
13826
|
+
}
|
|
13827
|
+
function createFlushSyncAct(flushSync) {
|
|
13828
|
+
return (callback) => {
|
|
13829
|
+
let callbackResult;
|
|
13830
|
+
flushSync(() => {
|
|
13831
|
+
callbackResult = callback();
|
|
13832
|
+
});
|
|
13833
|
+
if (isThenable(callbackResult)) {
|
|
13834
|
+
const pending = callbackResult;
|
|
13835
|
+
return new Promise((resolve3, reject) => {
|
|
13836
|
+
pending.then(() => resolve3(), reject);
|
|
13837
|
+
});
|
|
13838
|
+
}
|
|
13839
|
+
return new Promise((resolve3) => {
|
|
13840
|
+
queueMicrotask(resolve3);
|
|
13841
|
+
});
|
|
13842
|
+
};
|
|
13843
|
+
}
|
|
13844
|
+
function isThenable(value) {
|
|
13845
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
13846
|
+
}
|
|
14718
13847
|
|
|
14719
13848
|
// src/internal/open-record.ts
|
|
14720
13849
|
function openRecord(o) {
|
|
@@ -14832,6 +13961,7 @@ async function runRenderCheck(input) {
|
|
|
14832
13961
|
const probe = createProbe();
|
|
14833
13962
|
const wireConfig = createProbeWireConfig(probe);
|
|
14834
13963
|
uninstallSpy = probe.installPostMessageSpy();
|
|
13964
|
+
installProductionActShim();
|
|
14835
13965
|
const { render, cleanup } = await import('@testing-library/react');
|
|
14836
13966
|
const userEventModule = await import('@testing-library/user-event');
|
|
14837
13967
|
const userEvent = userEventModule.default ?? userEventModule;
|
|
@@ -14987,6 +14117,50 @@ async function runRenderCheck(input) {
|
|
|
14987
14117
|
if (issue) issues.push(issue);
|
|
14988
14118
|
}
|
|
14989
14119
|
}
|
|
14120
|
+
const declaredProps = input.contract?.propsSpec?.properties;
|
|
14121
|
+
if (declaredProps) {
|
|
14122
|
+
const optionalFilled = Object.entries(declaredProps).filter(
|
|
14123
|
+
([name, entry]) => entry.required !== true && input.mockupProps[name] !== void 0
|
|
14124
|
+
).map(([name]) => name);
|
|
14125
|
+
if (optionalFilled.length > 0) {
|
|
14126
|
+
const requiredOnlyProps = { ...input.mockupProps };
|
|
14127
|
+
for (const name of optionalFilled) delete requiredOnlyProps[name];
|
|
14128
|
+
const omitBoundaryRef = {};
|
|
14129
|
+
class OmitErrorBoundary extends React.Component {
|
|
14130
|
+
state = { caught: false };
|
|
14131
|
+
static getDerivedStateFromError() {
|
|
14132
|
+
return { caught: true };
|
|
14133
|
+
}
|
|
14134
|
+
componentDidCatch(error) {
|
|
14135
|
+
omitBoundaryRef.error ??= error;
|
|
14136
|
+
}
|
|
14137
|
+
render() {
|
|
14138
|
+
if (this.state.caught) return null;
|
|
14139
|
+
return this.props.children;
|
|
14140
|
+
}
|
|
14141
|
+
}
|
|
14142
|
+
try {
|
|
14143
|
+
render(
|
|
14144
|
+
React.createElement(GguiWireProvider, {
|
|
14145
|
+
config: wireConfig,
|
|
14146
|
+
children: React.createElement(OmitErrorBoundary, {
|
|
14147
|
+
children: React.createElement(Component, requiredOnlyProps)
|
|
14148
|
+
})
|
|
14149
|
+
})
|
|
14150
|
+
);
|
|
14151
|
+
} catch (e) {
|
|
14152
|
+
omitBoundaryRef.error ??= e instanceof Error ? e : new Error(String(e));
|
|
14153
|
+
}
|
|
14154
|
+
if (omitBoundaryRef.error) {
|
|
14155
|
+
issues.push({
|
|
14156
|
+
check: "optional-props-omitted",
|
|
14157
|
+
outcome: "failed",
|
|
14158
|
+
subject: optionalFilled.join(", "),
|
|
14159
|
+
reason: `Render crashed when the optional prop(s) ${optionalFilled.map((n) => `'${n}'`).join(", ")} were omitted: ${omitBoundaryRef.error.message}. The contract marks them optional (no \`required: true\`), so a legitimate render may leave them out.`
|
|
14160
|
+
});
|
|
14161
|
+
}
|
|
14162
|
+
}
|
|
14163
|
+
}
|
|
14990
14164
|
} finally {
|
|
14991
14165
|
cleanup();
|
|
14992
14166
|
}
|
|
@@ -15154,8 +14328,8 @@ async function setupHappyDom() {
|
|
|
15154
14328
|
};
|
|
15155
14329
|
}
|
|
15156
14330
|
const { Window } = await import('happy-dom');
|
|
15157
|
-
const
|
|
15158
|
-
const windowAny = openRecord(
|
|
14331
|
+
const window = new Window({ url: "https://render-check.local" });
|
|
14332
|
+
const windowAny = openRecord(window);
|
|
15159
14333
|
const keys = [
|
|
15160
14334
|
"window",
|
|
15161
14335
|
"document",
|
|
@@ -15558,6 +14732,15 @@ function synthesizeFromSchema(schema, hint, warnings, depth) {
|
|
|
15558
14732
|
if (schema.anyOf && schema.anyOf.length > 0) {
|
|
15559
14733
|
return synthesizeFromSchema(schema.anyOf[0], hint, warnings, depth + 1);
|
|
15560
14734
|
}
|
|
14735
|
+
if (Array.isArray(schema.type)) {
|
|
14736
|
+
const primary = schema.type.find((t) => t !== "null") ?? "null";
|
|
14737
|
+
return synthesizeFromSchema(
|
|
14738
|
+
{ ...schema, type: primary },
|
|
14739
|
+
hint,
|
|
14740
|
+
warnings,
|
|
14741
|
+
depth + 1
|
|
14742
|
+
);
|
|
14743
|
+
}
|
|
15561
14744
|
switch (schema.type) {
|
|
15562
14745
|
case "string": {
|
|
15563
14746
|
switch (schema.format) {
|
|
@@ -15728,6 +14911,16 @@ function toEvalIssue(issue) {
|
|
|
15728
14911
|
description: `Component crashed at runtime: ${issue.reason}`,
|
|
15729
14912
|
fix: classifyRenderCrashFix(issue.reason)
|
|
15730
14913
|
};
|
|
14914
|
+
case "optional-props-omitted":
|
|
14915
|
+
return {
|
|
14916
|
+
tier: 0,
|
|
14917
|
+
result,
|
|
14918
|
+
category: "crash",
|
|
14919
|
+
subcategory,
|
|
14920
|
+
severity: "critical",
|
|
14921
|
+
description: `Component crashed when optional props were omitted: ${issue.reason}`,
|
|
14922
|
+
fix: `Guard every optional prop before member access (props.${subject.split(",")[0]?.trim() ?? "x"}?.map(...), a default via destructuring, or an early empty-state return). Optional props (no \`required: true\` in the contract) may be absent at runtime even though the harness fills them.`
|
|
14923
|
+
};
|
|
15731
14924
|
case "action-wiring": {
|
|
15732
14925
|
const fix = issue.outcome === "unverified" ? `Source shows the action callback flowing into a non-native or custom-component prop. If wiring is intentional (e.g., Dropdown.onChange, drag-drop), this warn is informational \u2014 manual/browser verification is required to confirm. Otherwise wire to a native onClick={() => ${subject}(payload)} on <button> or design-system <Button>.` : `Wire ${subject}() to a native event prop. Common fix: <Button onClick={() => ${subject}(payload)}>Label</Button>. Source-AST analysis didn't find this wiring in your JSX.`;
|
|
15733
14926
|
return {
|
|
@@ -15774,6 +14967,7 @@ async function warmupRuntimeRenderProbe() {
|
|
|
15774
14967
|
missing += 1;
|
|
15775
14968
|
}
|
|
15776
14969
|
};
|
|
14970
|
+
installProductionActShim();
|
|
15777
14971
|
await Promise.all([
|
|
15778
14972
|
tryLoad("happy-dom"),
|
|
15779
14973
|
tryLoad("@testing-library/react"),
|
|
@@ -16858,6 +16052,14 @@ function mapProviderForEvaluator(provider) {
|
|
|
16858
16052
|
|
|
16859
16053
|
// src/harness/coding/run-eval-round.ts
|
|
16860
16054
|
var MAX_FEEDBACK_ISSUES = 3;
|
|
16055
|
+
function selectActionableFeedback(issues) {
|
|
16056
|
+
const pool = issues.filter((i) => i.result === "fail" || i.result === "warn");
|
|
16057
|
+
const reserved = pool.find((i) => i.tier === 0 && i.result === "fail");
|
|
16058
|
+
return [
|
|
16059
|
+
...reserved ? [reserved] : [],
|
|
16060
|
+
...pool.filter((i) => i !== reserved).sort((a, b) => (a.result === "fail" ? 0 : 1) - (b.result === "fail" ? 0 : 1))
|
|
16061
|
+
].slice(0, MAX_FEEDBACK_ISSUES);
|
|
16062
|
+
}
|
|
16861
16063
|
function fingerprintFail(issue) {
|
|
16862
16064
|
const cat = issue.category ?? "";
|
|
16863
16065
|
const sub = issue.subcategory ?? "";
|
|
@@ -17026,7 +16228,20 @@ async function runEvalRound(ctx, input) {
|
|
|
17026
16228
|
},
|
|
17027
16229
|
{
|
|
17028
16230
|
provider: mapProviderForEvaluator(evaluationAgent.provider),
|
|
17029
|
-
model: evaluationAgent.model
|
|
16231
|
+
model: evaluationAgent.model,
|
|
16232
|
+
// #484 — thread the coding-agent's routing override
|
|
16233
|
+
// through to the evaluator so its LLM call never falls
|
|
16234
|
+
// back to `process.env` either (the eval calls run
|
|
16235
|
+
// inside the same concurrent generation, so the race is
|
|
16236
|
+
// real here too, not just on the coding turn).
|
|
16237
|
+
routeOverride: evaluationAgent.routeOverride,
|
|
16238
|
+
// #489 — thread the same provider-429-retry observer.
|
|
16239
|
+
// Without this, a rate-limited retry inside the
|
|
16240
|
+
// evaluation agent's apiCall() happens (the base-class
|
|
16241
|
+
// retry loop is unconditional) but never reaches the
|
|
16242
|
+
// caller, silently missing the host application's
|
|
16243
|
+
// structured log.
|
|
16244
|
+
onRetry: evaluationAgent.onRetry
|
|
17030
16245
|
},
|
|
17031
16246
|
preWarmedContext
|
|
17032
16247
|
) : null,
|
|
@@ -17037,7 +16252,15 @@ async function runEvalRound(ctx, input) {
|
|
|
17037
16252
|
model: visualEvalAgent.model,
|
|
17038
16253
|
passThreshold: visualThreshold,
|
|
17039
16254
|
sampleProps: visualEvaluation?.sampleProps,
|
|
17040
|
-
viewport: visualEvaluation?.viewport
|
|
16255
|
+
viewport: visualEvaluation?.viewport,
|
|
16256
|
+
// #484/#489 — same threading as the LLM-eval leg above:
|
|
16257
|
+
// the visual eval's multimodal call runs inside the same
|
|
16258
|
+
// concurrent generation, so it needs the same routing
|
|
16259
|
+
// override (never fall back to `process.env`) and the
|
|
16260
|
+
// same provider-429-retry observer (retries reach the
|
|
16261
|
+
// host application's structured log).
|
|
16262
|
+
routeOverride: visualEvalAgent.routeOverride,
|
|
16263
|
+
onRetry: visualEvalAgent.onRetry
|
|
17041
16264
|
}
|
|
17042
16265
|
) : null
|
|
17043
16266
|
]);
|
|
@@ -17256,7 +16479,7 @@ async function runEvalRound(ctx, input) {
|
|
|
17256
16479
|
lastDiffFailed: false
|
|
17257
16480
|
};
|
|
17258
16481
|
}
|
|
17259
|
-
const allActionable = evalResult.issues
|
|
16482
|
+
const allActionable = selectActionableFeedback(evalResult.issues);
|
|
17260
16483
|
const issueLines = allActionable.map((issue) => {
|
|
17261
16484
|
const tag = issue.result === "fail" ? "FAIL" : "WARN";
|
|
17262
16485
|
return `[${tag}] ${issue.category}${issue.subcategory ? "/" + issue.subcategory : ""}: ${issue.description}
|
|
@@ -17271,7 +16494,16 @@ async function runEvalRound(ctx, input) {
|
|
|
17271
16494
|
evalResult,
|
|
17272
16495
|
evalRoundsUsed,
|
|
17273
16496
|
prevModeSubcats: updatedPrevModeSubcats,
|
|
17274
|
-
|
|
16497
|
+
// DELIVERED fails only (Exp 54 P1 addendum, proposal 2): the
|
|
16498
|
+
// stuck detector's premise is "the LLM saw these and did not
|
|
16499
|
+
// resolve them" — recording fails that the MAX_FEEDBACK_ISSUES
|
|
16500
|
+
// cap cut from the feedback turns truncation into a premature
|
|
16501
|
+
// stuck-exit (the model never saw the issue it is blamed for
|
|
16502
|
+
// not fixing). An undelivered fail recurring next round now
|
|
16503
|
+
// reads as NEW, gets delivered, and earns its fix round.
|
|
16504
|
+
prevFailFingerprints: new Set(
|
|
16505
|
+
allActionable.filter((i) => i.result === "fail").map(fingerprintFail)
|
|
16506
|
+
),
|
|
17275
16507
|
preWarmedContext,
|
|
17276
16508
|
evalTokens,
|
|
17277
16509
|
evalLlmMs,
|
|
@@ -17674,7 +16906,7 @@ async function initSession(input) {
|
|
|
17674
16906
|
await workspace.stage();
|
|
17675
16907
|
await workspace.commit("scaffold: boilerplate");
|
|
17676
16908
|
const systemPrompt = input.systemPromptOverride ?? harness.how.systemPrompt;
|
|
17677
|
-
const codingAgent = createAgent(agents.coding
|
|
16909
|
+
const codingAgent = createAgent(agents.coding);
|
|
17678
16910
|
await codingAgent.warmCache(
|
|
17679
16911
|
agents.coding.model,
|
|
17680
16912
|
systemPrompt,
|
|
@@ -17763,8 +16995,18 @@ async function dispatchGeneration(params) {
|
|
|
17763
16995
|
}
|
|
17764
16996
|
const routerProvider = mapProviderForLLMRouter(params.provider);
|
|
17765
16997
|
const resolvedModel = params.models?.coding ?? params.models?.default ?? params.model;
|
|
17766
|
-
const codingAgent = {
|
|
17767
|
-
|
|
16998
|
+
const codingAgent = {
|
|
16999
|
+
provider: routerProvider,
|
|
17000
|
+
model: resolvedModel,
|
|
17001
|
+
routeOverride: params.routeOverride,
|
|
17002
|
+
onRetry: params.onRetry
|
|
17003
|
+
};
|
|
17004
|
+
const evaluationAgent = params.models?.evaluation ? {
|
|
17005
|
+
provider: routerProvider,
|
|
17006
|
+
model: params.models.evaluation,
|
|
17007
|
+
routeOverride: params.routeOverride,
|
|
17008
|
+
onRetry: params.onRetry
|
|
17009
|
+
} : void 0;
|
|
17768
17010
|
const effectiveContract = params.contract;
|
|
17769
17011
|
const sessionParams = {
|
|
17770
17012
|
userPrompt: params.originalPrompt ?? params.userPrompt,
|