@koda-sl/baker-cli 0.295.0-dev.f941e60fb → 0.295.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/README.md +31 -87
- package/canvas/tiktok-captions-composition/index.html +2 -23
- package/dist/{chunk-2IUN3S3E.js → chunk-2IB3IL4K.js} +2 -2
- package/dist/{chunk-4YF56EGK.js → chunk-D3HHUBIL.js} +4 -4
- package/dist/{chunk-WFWU3CHS.js → chunk-DZUVUGEP.js} +1 -9
- package/dist/{chunk-WFWU3CHS.js.map → chunk-DZUVUGEP.js.map} +1 -1
- package/dist/{chunk-A2VZOTCV.js → chunk-EX2OIOVL.js} +3 -3
- package/dist/{chunk-KDTHRRAC.js → chunk-GU7IWEBC.js} +3 -3
- package/dist/{chunk-ER3KCAW3.js → chunk-YFQWCJX4.js} +123 -301
- package/dist/chunk-YFQWCJX4.js.map +1 -0
- package/dist/cli.js +1269 -2954
- package/dist/cli.js.map +1 -1
- package/dist/{client-6KQHCXS2.js → client-VDCCDEHE.js} +4 -4
- package/dist/engine/index.d.ts +0 -13
- package/dist/engine/index.js +3 -3
- package/dist/{env-C7YXL6C6.js → env-FWMZXMQK.js} +2 -6
- package/dist/{output-RBM32FKJ.js → output-4H2RNBXL.js} +5 -5
- package/dist/{shared-WJIJTWST.js → shared-UKL36AXT.js} +6 -6
- package/package.json +1 -1
- package/dist/chunk-ER3KCAW3.js.map +0 -1
- /package/dist/{chunk-2IUN3S3E.js.map → chunk-2IB3IL4K.js.map} +0 -0
- /package/dist/{chunk-4YF56EGK.js.map → chunk-D3HHUBIL.js.map} +0 -0
- /package/dist/{chunk-A2VZOTCV.js.map → chunk-EX2OIOVL.js.map} +0 -0
- /package/dist/{chunk-KDTHRRAC.js.map → chunk-GU7IWEBC.js.map} +0 -0
- /package/dist/{client-6KQHCXS2.js.map → client-VDCCDEHE.js.map} +0 -0
- /package/dist/{env-C7YXL6C6.js.map → env-FWMZXMQK.js.map} +0 -0
- /package/dist/{output-RBM32FKJ.js.map → output-4H2RNBXL.js.map} +0 -0
- /package/dist/{shared-WJIJTWST.js.map → shared-UKL36AXT.js.map} +0 -0
|
@@ -1,25 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
2
|
debugLogHttp,
|
|
3
3
|
readBodyForLog
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2IB3IL4K.js";
|
|
5
5
|
import {
|
|
6
6
|
DIRECT_ROUTE,
|
|
7
7
|
__commonJS,
|
|
8
8
|
__toESM,
|
|
9
9
|
captureProxyCredentials,
|
|
10
10
|
childEnvWith,
|
|
11
|
-
hasFrameVisionKey,
|
|
12
11
|
isChallengeBody,
|
|
13
12
|
isPrivateAddress,
|
|
14
13
|
isProxyFailure,
|
|
15
14
|
plannedRoutes,
|
|
16
15
|
refuseNonPublicUrl,
|
|
17
16
|
shouldEscalate
|
|
18
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DZUVUGEP.js";
|
|
19
18
|
|
|
20
|
-
//
|
|
19
|
+
// ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
|
|
21
20
|
var require_safe_stable_stringify = __commonJS({
|
|
22
|
-
"
|
|
21
|
+
"../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
|
|
23
22
|
"use strict";
|
|
24
23
|
var { hasOwnProperty } = Object.prototype;
|
|
25
24
|
var stringify = configure2();
|
|
@@ -758,6 +757,19 @@ async function parseErrorBody(res) {
|
|
|
758
757
|
}
|
|
759
758
|
return classifyHttpError(res.status, errObj, message2);
|
|
760
759
|
}
|
|
760
|
+
function providerVerdict(status, errObj, message2) {
|
|
761
|
+
if (errObj.provider === void 0 && errObj.code !== "provider_error") return null;
|
|
762
|
+
return {
|
|
763
|
+
kind: "provider",
|
|
764
|
+
status,
|
|
765
|
+
provider: errObj.provider,
|
|
766
|
+
code: errObj.code ?? "provider_error",
|
|
767
|
+
message: message2,
|
|
768
|
+
// A 4xx is terminal unless the backend says otherwise — the opposite
|
|
769
|
+
// default from the 502 branch, where the status itself means "try again".
|
|
770
|
+
retryable: errObj.retryable ?? false
|
|
771
|
+
};
|
|
772
|
+
}
|
|
761
773
|
function classifyHttpError(status, errObj, message2) {
|
|
762
774
|
if (errObj.code === CONTENT_POLICY_CODE) {
|
|
763
775
|
return { kind: "content_policy", status, provider: errObj.provider, message: message2 };
|
|
@@ -766,7 +778,7 @@ function classifyHttpError(status, errObj, message2) {
|
|
|
766
778
|
return { kind: "unauthorized", status, message: message2 };
|
|
767
779
|
}
|
|
768
780
|
if (status === 400 || status === 422) {
|
|
769
|
-
return { kind: "validation", status, message: message2, details: errObj.details };
|
|
781
|
+
return providerVerdict(status, errObj, message2) ?? { kind: "validation", status, message: message2, details: errObj.details };
|
|
770
782
|
}
|
|
771
783
|
if (status === 502 || status === 504) {
|
|
772
784
|
if (errObj.code === "provider_timeout" || status === 504) {
|
|
@@ -1034,17 +1046,12 @@ function failureDetail(reason) {
|
|
|
1034
1046
|
}
|
|
1035
1047
|
return { message: describeFailureReason(reason) };
|
|
1036
1048
|
}
|
|
1037
|
-
function retryVerdict(retryable) {
|
|
1038
|
-
if (retryable === true) return "transient \u2014 retry the run";
|
|
1039
|
-
if (retryable === false) return "not retryable \u2014 retrying will not help, fix the input";
|
|
1040
|
-
return "retryability unknown";
|
|
1041
|
-
}
|
|
1042
1049
|
function describeCause(c) {
|
|
1043
1050
|
switch (c.kind) {
|
|
1044
1051
|
case "local":
|
|
1045
1052
|
return c.cause instanceof Error ? c.cause.message : String(c.cause);
|
|
1046
1053
|
case "remote":
|
|
1047
|
-
return `[${c.code}] ${c.message}${c.provider ? ` (${c.provider})` : ""}
|
|
1054
|
+
return `[${c.code}] ${c.message}${c.provider ? ` (${c.provider})` : ""}`;
|
|
1048
1055
|
case "timeout":
|
|
1049
1056
|
return `timeout${c.provider ? ` (${c.provider})` : ""}`;
|
|
1050
1057
|
case "network":
|
|
@@ -1098,7 +1105,7 @@ function resolveAdaptFormats(params) {
|
|
|
1098
1105
|
return params.formats ?? [];
|
|
1099
1106
|
}
|
|
1100
1107
|
|
|
1101
|
-
//
|
|
1108
|
+
// ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
|
|
1102
1109
|
var import__ = __toESM(require_safe_stable_stringify(), 1);
|
|
1103
1110
|
var configure = import__.default.configure;
|
|
1104
1111
|
var wrapper_default = import__.default;
|
|
@@ -1139,14 +1146,6 @@ function normalizeForCanonical(value) {
|
|
|
1139
1146
|
return void 0;
|
|
1140
1147
|
}
|
|
1141
1148
|
|
|
1142
|
-
// ../canvas-contract/src/frameRealism.ts
|
|
1143
|
-
function frameRealismDirection(opts = {}) {
|
|
1144
|
-
return " Everything obeys real-world physics: paper, card and screens are OPAQUE with nothing showing through from behind, every object is at believable real-world scale next to the people handling it, and every object has its real-world form and construction \u2014 a phone has ONE screen and it is on the front. NO readable text or numbers anywhere in frame \u2014 phone screens, documents and signage stay illegible or out of focus, because any figure the model invents will contradict the script. Hands are kept simple: no close-up of fingers manipulating small parts, no hand gripping the edge of an object, and each person has exactly TWO arms and TWO legs, all attached and all visible or all out of frame. Anyone working does so the way the trade actually does it: nobody stands or kneels on the equipment being installed, nothing is fitted overhanging an edge or floating unsupported, and every part rests on the structure that would really carry it." + // The newest clause, and the one no route had. A testimonial came back with the customer
|
|
1145
|
-
// repairing the panel herself: nothing said she was not the installer, so the model cast
|
|
1146
|
-
// her as one. Who someone IS in the picture has to be stated, or it is guessed.
|
|
1147
|
-
(opts.role ? ` The person on camera is ${opts.role} \u2014 they are shown as that and never doing somebody else's job.` : "") + (opts.currency ? ` If a currency is unavoidably visible it is ${opts.currency}.` : "");
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
1149
|
// ../canvas-contract/src/registry.ts
|
|
1151
1150
|
var OPENROUTER_IMAGE_AR = ["1:1", "2:3", "3:2", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
|
|
1152
1151
|
var OPENROUTER_IMAGE_AR_EXTREME = [...OPENROUTER_IMAGE_AR, "1:4", "4:1", "1:8", "8:1"];
|
|
@@ -1166,7 +1165,6 @@ var OPENROUTER_IMAGE_SIZES = ["0.5K", ...OPENROUTER_IMAGE_SIZE];
|
|
|
1166
1165
|
var OPENROUTER_IMAGE_SIZE_EXTENDED = OPENROUTER_IMAGE_SIZES;
|
|
1167
1166
|
var GEMINI_LITE_IMAGE_SIZE = ["1K"];
|
|
1168
1167
|
var OPENROUTER_IMAGE_QUALITY = ["auto", "low", "medium", "high"];
|
|
1169
|
-
var OPENROUTER_IMAGE_QUALITY_25 = ["auto", "low", "medium", "high", "xhigh", "max"];
|
|
1170
1168
|
var RECRAFT_IMAGE_AR = ["1:1", "4:3", "3:4", "16:9", "9:16"];
|
|
1171
1169
|
var SEEDANCE_DURATIONS = [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
|
|
1172
1170
|
var SEEDANCE_25_DURATIONS = [
|
|
@@ -1229,7 +1227,6 @@ var REPLICATE_VIDEO_MIMES = ["video/mp4", "video/webm", "video/quicktime"];
|
|
|
1229
1227
|
var DECONSTRUCT_VIDEO_MIMES = ["video/mp4", "video/webm", "video/quicktime"];
|
|
1230
1228
|
var REPLICATE_AUDIO_MIMES = ["audio/wav", "audio/mpeg", "audio/mp3"];
|
|
1231
1229
|
var IMAGE_GENERATE_MODELS = [
|
|
1232
|
-
"openai/gpt-image-2.5-sunburst",
|
|
1233
1230
|
"openai/gpt-image-2",
|
|
1234
1231
|
"openai/gpt-5.4-image-2",
|
|
1235
1232
|
"google/gemini-3.1-flash-image-preview",
|
|
@@ -1375,20 +1372,6 @@ var MODEL_REGISTRY = {
|
|
|
1375
1372
|
// images as a side effect. Notable capability gaps vs the Gemini entries:
|
|
1376
1373
|
// no `image_size` (OpenAI picks the pixel dimensions from the ratio, and a
|
|
1377
1374
|
// `resolution` is silently ignored) and the narrower `..._AR_GPT` ratio set.
|
|
1378
|
-
"openai/gpt-image-2.5-sunburst": {
|
|
1379
|
-
// Identical to the gpt-image-2 entry below except for the quality ladder — the
|
|
1380
|
-
// ratio set, the 16-reference ceiling, the missing `image_size` and the reasons
|
|
1381
|
-
// `background` / `output_compression` stay undeclared all carry over unchanged.
|
|
1382
|
-
label: "OpenAI GPT Image 2.5",
|
|
1383
|
-
inputs: [],
|
|
1384
|
-
optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES, max: GPT_IMAGE_MAX_REFERENCES }],
|
|
1385
|
-
required: ["prompt"],
|
|
1386
|
-
params: {
|
|
1387
|
-
prompt: { kind: "string", maxLength: GPT_IMAGE_PROMPT_MAX },
|
|
1388
|
-
aspect_ratio: { kind: "string", enum: OPENROUTER_IMAGE_AR_GPT },
|
|
1389
|
-
quality: { kind: "string", enum: OPENROUTER_IMAGE_QUALITY_25 }
|
|
1390
|
-
}
|
|
1391
|
-
},
|
|
1392
1375
|
"openai/gpt-image-2": {
|
|
1393
1376
|
// Its live endpoint also advertises `background` (auto|opaque) and
|
|
1394
1377
|
// `output_compression` (0-100), which we deliberately do not declare. Not an
|
|
@@ -2043,15 +2026,6 @@ function supportsParam(kind, model, param) {
|
|
|
2043
2026
|
return MODEL_REGISTRY[kind]?.[model]?.params[param] !== void 0;
|
|
2044
2027
|
}
|
|
2045
2028
|
var DEFAULT_CLIP_DURATION_S = 5;
|
|
2046
|
-
var SPOKEN_WORDS_PER_SECOND = 2.5;
|
|
2047
|
-
function spokenWordsIn(prompt) {
|
|
2048
|
-
if (!prompt) return 0;
|
|
2049
|
-
const quoted = [
|
|
2050
|
-
...prompt.matchAll(/['"\u201c\u201d\u2018\u2019]([^'"\u201c\u201d\u2018\u2019]{8,})['"\u201c\u201d\u2018\u2019]/g)
|
|
2051
|
-
].map((m) => m[1] ?? "");
|
|
2052
|
-
const text = quoted.join(" ").trim();
|
|
2053
|
-
return text ? text.split(/\s+/).filter(Boolean).length : 0;
|
|
2054
|
-
}
|
|
2055
2029
|
function nearestClipDuration(model, preferred) {
|
|
2056
2030
|
const schema = MODEL_REGISTRY.video_generate[model]?.params.duration;
|
|
2057
2031
|
const allowed = schema?.kind === "number" ? schema.enum : void 0;
|
|
@@ -2072,19 +2046,6 @@ function maxInputSlot(kind, model, inputKind) {
|
|
|
2072
2046
|
function maxInputReferences(kind, model) {
|
|
2073
2047
|
return maxInputSlot(kind, model, "image");
|
|
2074
2048
|
}
|
|
2075
|
-
function supportedQualities(kind, model) {
|
|
2076
|
-
const schema = MODEL_REGISTRY[kind]?.[model]?.params.quality;
|
|
2077
|
-
return schema?.kind === "string" ? schema.enum : void 0;
|
|
2078
|
-
}
|
|
2079
|
-
function bestSupportedQuality(kind, model, want) {
|
|
2080
|
-
const supported = supportedQualities(kind, model);
|
|
2081
|
-
if (!supported) return void 0;
|
|
2082
|
-
if (supported.includes(want)) return want;
|
|
2083
|
-
const ladder = supported.filter((step) => step !== "auto");
|
|
2084
|
-
const ceiling = ladder.indexOf(want);
|
|
2085
|
-
const reachable = ceiling === -1 ? ladder : ladder.slice(0, ceiling);
|
|
2086
|
-
return reachable[reachable.length - 1];
|
|
2087
|
-
}
|
|
2088
2049
|
function supportedAspectRatios(kind, model) {
|
|
2089
2050
|
const schema = MODEL_REGISTRY[kind]?.[model]?.params.aspect_ratio;
|
|
2090
2051
|
return schema?.kind === "string" ? schema.enum : void 0;
|
|
@@ -3169,16 +3130,6 @@ function dfsCycle(u, color, stack, reverseAdj) {
|
|
|
3169
3130
|
stack.pop();
|
|
3170
3131
|
return null;
|
|
3171
3132
|
}
|
|
3172
|
-
function nodesBeforeCheckpoint(graph, types, stopKinds) {
|
|
3173
|
-
const all = new Set(graph.keys());
|
|
3174
|
-
if (!stopKinds?.size) return all;
|
|
3175
|
-
const running = /* @__PURE__ */ new Set();
|
|
3176
|
-
for (const layer of topologicalLayers(graph)) {
|
|
3177
|
-
if (layer.some((id) => stopKinds.has(types.get(id) ?? ""))) return running;
|
|
3178
|
-
for (const id of layer) running.add(id);
|
|
3179
|
-
}
|
|
3180
|
-
return running;
|
|
3181
|
-
}
|
|
3182
3133
|
|
|
3183
3134
|
// src/engine/engine/validator.ts
|
|
3184
3135
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -3197,7 +3148,7 @@ var VEO_DURATIONS = [4, 6, 8];
|
|
|
3197
3148
|
var KLING_DURATIONS2 = [5, 10];
|
|
3198
3149
|
var KLING_NEGATIVE_PROMPT = "warped face, distorted hands, extra fingers, morphing, flicker, on-screen text, watermark, low quality";
|
|
3199
3150
|
var KLING_CFG_SCALE = 0.7;
|
|
3200
|
-
var SPEAKS_PROSE = (line
|
|
3151
|
+
var SPEAKS_PROSE = (line) => `The person speaks to camera; lip-sync follows the dialogue verbatim, with delivery and emotion carried in the wording itself (no bracketed cues). Dialogue: "${line}"`;
|
|
3201
3152
|
var SEEDANCE_PROFILE = {
|
|
3202
3153
|
id: "seedance",
|
|
3203
3154
|
dialogueDirective: SPEAKS_PROSE,
|
|
@@ -3298,14 +3249,9 @@ var GPT_IMAGE_PROFILE = {
|
|
|
3298
3249
|
id: "gpt-image",
|
|
3299
3250
|
constraintPlacement: "last",
|
|
3300
3251
|
photorealCue: true,
|
|
3301
|
-
// OpenRouter forwards `quality`; gpt-image already processes inputs at high
|
|
3302
|
-
// automatically, so we deliberately do NOT send `input_fidelity`.
|
|
3303
|
-
|
|
3304
|
-
// No `quality` here any more: it is the one default that depends on WHICH gpt-image is
|
|
3305
|
-
// pinned. 2.5 added `xhigh` and `max` above `high`, and the older entries would refuse
|
|
3306
|
-
// them at validate — so callers ask for the step they want through
|
|
3307
|
-
// `bestSupportedQuality` and get the best the chosen model actually has.
|
|
3308
|
-
paramDefaults: {}
|
|
3252
|
+
// OpenRouter forwards `quality`; gpt-image-2 already processes inputs at high
|
|
3253
|
+
// fidelity automatically, so we deliberately do NOT send `input_fidelity`.
|
|
3254
|
+
paramDefaults: { quality: "high" }
|
|
3309
3255
|
};
|
|
3310
3256
|
var GEMINI_IMAGE_PROFILE = {
|
|
3311
3257
|
id: "gemini",
|
|
@@ -3816,19 +3762,6 @@ function checkSlotsForNode(ctx, n, _i) {
|
|
|
3816
3762
|
});
|
|
3817
3763
|
}
|
|
3818
3764
|
}
|
|
3819
|
-
function estimateCreditsFor(canvas, registry, ids) {
|
|
3820
|
-
let total = 0;
|
|
3821
|
-
for (const n of canvas.nodes) {
|
|
3822
|
-
if (!ids.has(n.id)) continue;
|
|
3823
|
-
const def = registry.get(n.type);
|
|
3824
|
-
if (!def?.cost) continue;
|
|
3825
|
-
try {
|
|
3826
|
-
total += def.cost({ params: def.params.parse(n.params ?? {}) }).credits;
|
|
3827
|
-
} catch {
|
|
3828
|
-
}
|
|
3829
|
-
}
|
|
3830
|
-
return total;
|
|
3831
|
-
}
|
|
3832
3765
|
function estimateCredits(ctx) {
|
|
3833
3766
|
let total = 0;
|
|
3834
3767
|
for (const n of ctx.canvas.nodes) {
|
|
@@ -4135,7 +4068,7 @@ function checkAudioTimelineTotals(ctx, audioMixNode, expected) {
|
|
|
4135
4068
|
if (audioMixNode) mustBeFullLength.add(audioMixNode);
|
|
4136
4069
|
ctx.canvas.nodes.forEach((n) => {
|
|
4137
4070
|
if (n.type !== "audio_voice_convert") return;
|
|
4138
|
-
const track = refNodeOf(ctx, n.inputs
|
|
4071
|
+
const track = refNodeOf(ctx, (n.inputs ?? {}).audio);
|
|
4139
4072
|
if (track?.type === "audio_timeline") mustBeFullLength.add(track.id);
|
|
4140
4073
|
});
|
|
4141
4074
|
for (const id of mustBeFullLength) {
|
|
@@ -4156,11 +4089,11 @@ function checkAudioTimelineTotals(ctx, audioMixNode, expected) {
|
|
|
4156
4089
|
function checkNativeSegOverlap(ctx) {
|
|
4157
4090
|
for (const conv of ctx.canvas.nodes) {
|
|
4158
4091
|
if (conv.type !== "audio_voice_convert") continue;
|
|
4159
|
-
const track = refNodeOf(ctx, conv.inputs
|
|
4092
|
+
const track = refNodeOf(ctx, (conv.inputs ?? {}).audio);
|
|
4160
4093
|
if (track?.type !== "audio_timeline") continue;
|
|
4161
4094
|
const params = track.params;
|
|
4162
4095
|
const windows = (params.tracks ?? []).map((t) => {
|
|
4163
|
-
const extract = refNodeOf(ctx, track.inputs
|
|
4096
|
+
const extract = refNodeOf(ctx, (track.inputs ?? {})[t.slot]);
|
|
4164
4097
|
const len = t.duration_s ?? (extract ? ffmpegTrimSeconds(extract) : null);
|
|
4165
4098
|
return len === null ? null : { slot: t.slot, start: t.start_s, end: t.start_s + len };
|
|
4166
4099
|
}).filter((w) => w !== null).sort((a, b) => a.start - b.start);
|
|
@@ -4653,13 +4586,6 @@ function unwrap(schema) {
|
|
|
4653
4586
|
}
|
|
4654
4587
|
|
|
4655
4588
|
// src/engine/engine/executor.ts
|
|
4656
|
-
function heldByCheckpoint(canvas, layer, kinds) {
|
|
4657
|
-
if (!kinds?.size) return [];
|
|
4658
|
-
return layer.filter((id) => {
|
|
4659
|
-
const type = canvas.nodes.find((n) => n.id === id)?.type;
|
|
4660
|
-
return type !== void 0 && kinds.has(type);
|
|
4661
|
-
});
|
|
4662
|
-
}
|
|
4663
4589
|
var Engine = class {
|
|
4664
4590
|
registry;
|
|
4665
4591
|
client;
|
|
@@ -4687,7 +4613,7 @@ var Engine = class {
|
|
|
4687
4613
|
async run(input, opts = {}) {
|
|
4688
4614
|
const validation = await this.validateDeep(input);
|
|
4689
4615
|
if (!validation.ok) throw new ValidationError(validation.issues);
|
|
4690
|
-
if (
|
|
4616
|
+
if (opts.max_credits !== void 0 && validation.estimatedCredits > opts.max_credits) {
|
|
4691
4617
|
throw new RunAbortedError(
|
|
4692
4618
|
"cost_cap",
|
|
4693
4619
|
`estimated ${validation.estimatedCredits} credits exceeds the ${opts.max_credits}-credit cap \u2014 nothing was billed; raise --max-credits or shrink the canvas`
|
|
@@ -4706,20 +4632,6 @@ var Engine = class {
|
|
|
4706
4632
|
const counters = { cachedNodes: 0, totalCredits: 0 };
|
|
4707
4633
|
const nodeRuns = [];
|
|
4708
4634
|
const graph = this.pruneToOutput(canvas, buildGraph(canvas));
|
|
4709
|
-
if (opts.max_credits !== void 0 && opts.stop_before_kinds?.size) {
|
|
4710
|
-
const willRun = nodesBeforeCheckpoint(
|
|
4711
|
-
graph,
|
|
4712
|
-
new Map(canvas.nodes.map((n) => [n.id, n.type])),
|
|
4713
|
-
opts.stop_before_kinds
|
|
4714
|
-
);
|
|
4715
|
-
const estimate = estimateCreditsFor(canvas, this.registry, willRun);
|
|
4716
|
-
if (estimate > opts.max_credits) {
|
|
4717
|
-
throw new RunAbortedError(
|
|
4718
|
-
"cost_cap",
|
|
4719
|
-
`estimated ${estimate} credits exceeds the ${opts.max_credits}-credit cap \u2014 nothing was billed; raise --max-credits or shrink the canvas`
|
|
4720
|
-
);
|
|
4721
|
-
}
|
|
4722
|
-
}
|
|
4723
4635
|
const needsBytes = computeNeedsLocalBytes(canvas, graph, this.registry);
|
|
4724
4636
|
this.emitProgress(opts, {
|
|
4725
4637
|
kind: "plan",
|
|
@@ -4764,13 +4676,6 @@ var Engine = class {
|
|
|
4764
4676
|
`spent ${counters.totalCredits} credits, over the ${opts.max_credits}-credit cap \u2014 completed nodes are cached; raise --max-credits to continue where this stopped`
|
|
4765
4677
|
);
|
|
4766
4678
|
}
|
|
4767
|
-
const held = heldByCheckpoint(canvas, layer, opts.stop_before_kinds);
|
|
4768
|
-
if (held.length > 0) {
|
|
4769
|
-
throw new RunAbortedError(
|
|
4770
|
-
"checkpoint",
|
|
4771
|
-
`stopped before ${held.join(", ")} \u2014 everything up to here is done and cached, so continuing this run id pays for none of it again`
|
|
4772
|
-
);
|
|
4773
|
-
}
|
|
4774
4679
|
const settled = await mapWithConcurrency(layer, limit, (nodeId) => {
|
|
4775
4680
|
if (opts.signal?.aborted) {
|
|
4776
4681
|
return Promise.reject(new RunAbortedError("signal", "run aborted before node dispatch"));
|
|
@@ -6044,7 +5949,7 @@ function resolveStrategy(params) {
|
|
|
6044
5949
|
case "text": {
|
|
6045
5950
|
const p = safePathname(params.url);
|
|
6046
5951
|
const isRawText = RAW_TEXT_EXTENSIONS.some((ext) => p.endsWith(ext));
|
|
6047
|
-
return isRawText ? "direct_fetch" : "
|
|
5952
|
+
return isRawText ? "direct_fetch" : "firecrawl";
|
|
6048
5953
|
}
|
|
6049
5954
|
default: {
|
|
6050
5955
|
params.expect;
|
|
@@ -6061,10 +5966,10 @@ function safePathname(rawUrl) {
|
|
|
6061
5966
|
}
|
|
6062
5967
|
var ingestNode = defineNode({
|
|
6063
5968
|
id: "ingest",
|
|
6064
|
-
version: "1.
|
|
5969
|
+
version: "1.3.0",
|
|
6065
5970
|
category: "io",
|
|
6066
5971
|
location: "local",
|
|
6067
|
-
summary: "Ingest an external URL or a local file into the asset store. Declare the kind you expect (image/video/audio/text/json/font); the node picks the strategy. For source=url: yt-dlp for video/audio (YouTube/TikTok/Vimeo/etc. and direct file URLs),
|
|
5972
|
+
summary: "Ingest an external URL or a local file into the asset store. Declare the kind you expect (image/video/audio/text/json/font); the node picks the strategy. For source=url: yt-dlp for video/audio (YouTube/TikTok/Vimeo/etc. and direct file URLs), Firecrawl for HTML/PDF pages \u2192 markdown, direct HTTP fetch for binary URLs (images, fonts) and raw .txt/.md. For source=path: read from the local filesystem and upload to R2.",
|
|
6068
5973
|
when_to_use: 'Use as the on-ramp for any external asset a canvas needs. `expect` makes the output port statically typed so downstream wiring is checked before any byte is fetched. Pick `source: "url"` for portable canvas; pick `source: "path"` for local files (canvas is not portable across machines without the file). Compose with other nodes for richer pipelines (e.g. `ingest expect=video` \u2192 `video_transcribe`).',
|
|
6069
5974
|
inputs: IngestInputs,
|
|
6070
5975
|
params: IngestParams,
|
|
@@ -6091,8 +5996,8 @@ function runStrategy(strategy, params, ctx) {
|
|
|
6091
5996
|
switch (strategy) {
|
|
6092
5997
|
case "direct_fetch":
|
|
6093
5998
|
return execDirectFetch(params, ctx);
|
|
6094
|
-
case "
|
|
6095
|
-
return
|
|
5999
|
+
case "firecrawl":
|
|
6000
|
+
return execFirecrawl(params, ctx);
|
|
6096
6001
|
case "yt_dlp":
|
|
6097
6002
|
return execYtDlp(params, ctx);
|
|
6098
6003
|
case "local_file":
|
|
@@ -6130,9 +6035,8 @@ async function ingestImageUrl(url, ctx) {
|
|
|
6130
6035
|
} catch (e) {
|
|
6131
6036
|
throw localExecError(ctx, `${url}: ${e.message}`);
|
|
6132
6037
|
}
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
}
|
|
6038
|
+
const note = normalizationNote(normalized);
|
|
6039
|
+
if (note) ctx.log(`ingest: ${url} ${note}`);
|
|
6136
6040
|
return uploadAndIngest({
|
|
6137
6041
|
bytes: normalized.bytes,
|
|
6138
6042
|
kind: "image",
|
|
@@ -6146,11 +6050,11 @@ async function ingestImageUrl(url, ctx) {
|
|
|
6146
6050
|
ctx
|
|
6147
6051
|
});
|
|
6148
6052
|
}
|
|
6149
|
-
async function
|
|
6053
|
+
async function execFirecrawl(params, ctx) {
|
|
6150
6054
|
const result = await callBackendExec({
|
|
6151
6055
|
nodeType: "ingest",
|
|
6152
6056
|
nodeVersion: ingestNode.version,
|
|
6153
|
-
params: { strategy: "
|
|
6057
|
+
params: { strategy: "firecrawl", url: params.url },
|
|
6154
6058
|
inputs: {},
|
|
6155
6059
|
outputKinds: { asset: "text" },
|
|
6156
6060
|
ctx
|
|
@@ -6242,23 +6146,69 @@ async function rasterizeSvgToPng(bytes) {
|
|
|
6242
6146
|
return await sharp(bytes, { density }).png({ force: true, palette: false }).toBuffer();
|
|
6243
6147
|
}
|
|
6244
6148
|
var MODEL_SAFE_IMAGE_MIMES = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/gif", "image/webp"]);
|
|
6245
|
-
|
|
6149
|
+
var MAX_MODEL_REFERENCE_BYTES = 30 * 1024 * 1024;
|
|
6150
|
+
async function fitWithinReferenceLimit(bytes, mime, maxBytes) {
|
|
6151
|
+
if (bytes.byteLength <= maxBytes) return { bytes, mime };
|
|
6152
|
+
const { default: sharp } = await import("sharp");
|
|
6153
|
+
const read = () => sharp(bytes, { animated: true });
|
|
6154
|
+
const meta = await read().metadata();
|
|
6155
|
+
const animated = (meta.pages ?? 1) > 1;
|
|
6156
|
+
const keepAlpha = meta.hasAlpha === true;
|
|
6157
|
+
const width = meta.width ?? 0;
|
|
6158
|
+
const encode = async (scale2) => {
|
|
6159
|
+
let pipeline2 = read();
|
|
6160
|
+
if (scale2 < 1 && width > 0) pipeline2 = pipeline2.resize({ width: Math.max(256, Math.round(width * scale2)) });
|
|
6161
|
+
if (animated && mime === "image/gif") return { bytes: await pipeline2.gif().toBuffer(), mime: "image/gif" };
|
|
6162
|
+
if (animated || keepAlpha) return { bytes: await pipeline2.webp({ quality: 90 }).toBuffer(), mime: "image/webp" };
|
|
6163
|
+
return { bytes: await pipeline2.jpeg({ quality: 90, mozjpeg: true }).toBuffer(), mime: "image/jpeg" };
|
|
6164
|
+
};
|
|
6165
|
+
let out = await encode(1);
|
|
6166
|
+
let scale = 1;
|
|
6167
|
+
for (let pass = 0; pass < 4 && out.bytes.byteLength > maxBytes; pass++) {
|
|
6168
|
+
scale *= Math.min(0.9, Math.sqrt(maxBytes / out.bytes.byteLength));
|
|
6169
|
+
out = await encode(scale);
|
|
6170
|
+
}
|
|
6171
|
+
return out;
|
|
6172
|
+
}
|
|
6173
|
+
async function toModelSafeImage(bytes, opts) {
|
|
6174
|
+
const maxBytes = opts?.maxBytes ?? MAX_MODEL_REFERENCE_BYTES;
|
|
6175
|
+
const fit = async (candidate, mime, rasterizedFrom) => {
|
|
6176
|
+
const fitted = await fitWithinReferenceLimit(candidate, mime, maxBytes);
|
|
6177
|
+
return {
|
|
6178
|
+
bytes: fitted.bytes,
|
|
6179
|
+
mime: fitted.mime,
|
|
6180
|
+
...rasterizedFrom ? { rasterizedFrom } : {},
|
|
6181
|
+
...fitted.bytes === candidate ? {} : { shrunkFromBytes: candidate.byteLength }
|
|
6182
|
+
};
|
|
6183
|
+
};
|
|
6246
6184
|
const safe = sniffImageMime(bytes);
|
|
6247
6185
|
if (safe && MODEL_SAFE_IMAGE_MIMES.has(safe)) {
|
|
6248
|
-
return
|
|
6186
|
+
return await fit(bytes, safe);
|
|
6249
6187
|
}
|
|
6250
6188
|
if (sniffSvg(bytes)) {
|
|
6251
|
-
return
|
|
6189
|
+
return await fit(await rasterizeSvgToPng(bytes), "image/png", "svg");
|
|
6252
6190
|
}
|
|
6253
6191
|
const { default: sharp } = await import("sharp");
|
|
6192
|
+
let png;
|
|
6193
|
+
let format;
|
|
6254
6194
|
try {
|
|
6255
6195
|
const img = sharp(bytes);
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
return { bytes: png, mime: "image/png", rasterizedFrom: format ?? "unknown" };
|
|
6196
|
+
format = (await img.metadata()).format ?? "unknown";
|
|
6197
|
+
png = await img.png({ force: true }).toBuffer();
|
|
6259
6198
|
} catch (e) {
|
|
6260
6199
|
throw new Error(`bytes are not a decodable image (${e.message})`);
|
|
6261
6200
|
}
|
|
6201
|
+
return await fit(png, "image/png", format);
|
|
6202
|
+
}
|
|
6203
|
+
function normalizationNote(image) {
|
|
6204
|
+
const parts = [];
|
|
6205
|
+
if (image.rasterizedFrom) parts.push(`normalized ${image.rasterizedFrom} -> ${image.mime}`);
|
|
6206
|
+
if (image.shrunkFromBytes !== void 0) {
|
|
6207
|
+
parts.push(
|
|
6208
|
+
`fitted ${image.shrunkFromBytes}B -> ${image.bytes.length}B as ${image.mime} (providers refuse a reference over ${MAX_MODEL_REFERENCE_BYTES}B)`
|
|
6209
|
+
);
|
|
6210
|
+
}
|
|
6211
|
+
return parts.length > 0 ? parts.join("; ") : null;
|
|
6262
6212
|
}
|
|
6263
6213
|
function hasAscii(buf, offset, sig) {
|
|
6264
6214
|
return buf.length >= offset + sig.length && buf.toString("ascii", offset, offset + sig.length) === sig;
|
|
@@ -6388,7 +6338,8 @@ async function execLocalFile(params, ctx) {
|
|
|
6388
6338
|
outBytes = normalized.bytes;
|
|
6389
6339
|
outMime = normalized.mime;
|
|
6390
6340
|
rasterizedFrom = normalized.rasterizedFrom;
|
|
6391
|
-
|
|
6341
|
+
const note = normalizationNote(normalized);
|
|
6342
|
+
if (note) ctx.log(`ingest: ${note}`);
|
|
6392
6343
|
}
|
|
6393
6344
|
const durationMs = probeVideoDurationMs(params.expect, outBytes, ctx);
|
|
6394
6345
|
const ref = await uploadAndIngest({
|
|
@@ -7360,24 +7311,6 @@ import { execFile as execFile3 } from "child_process";
|
|
|
7360
7311
|
import { readFile as readFile9 } from "fs/promises";
|
|
7361
7312
|
import path12 from "path";
|
|
7362
7313
|
import { promisify as promisify3 } from "util";
|
|
7363
|
-
|
|
7364
|
-
// src/engine/nodes/local/lib/caption-style.ts
|
|
7365
|
-
var TERMINAL = /[.,;:!?…]$/;
|
|
7366
|
-
function captionTextsFrom(html) {
|
|
7367
|
-
const cards = html.match(/<div[^>]*class="[^"]*\bcaption\b[^"]*"[\s\S]*?<\/div>/g) ?? [];
|
|
7368
|
-
return cards.map(
|
|
7369
|
-
(card) => card.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim()
|
|
7370
|
-
).filter((text) => text.length > 0);
|
|
7371
|
-
}
|
|
7372
|
-
function fragmentedCaptions(texts) {
|
|
7373
|
-
if (texts.length < 2) return null;
|
|
7374
|
-
const fragments = texts.slice(0, -1).filter((t) => !TERMINAL.test(t));
|
|
7375
|
-
if (fragments.length === 0) return null;
|
|
7376
|
-
const example = fragments[0];
|
|
7377
|
-
return `${fragments.length} of ${texts.length} caption cards end mid-clause, e.g. "${example}". Split captions where the script punctuates, not on a word count \u2014 a card that ends bare is a sentence cut in half by a timing decision, and it reads as one.`;
|
|
7378
|
-
}
|
|
7379
|
-
|
|
7380
|
-
// src/engine/nodes/local/lib/hyperframe-check.ts
|
|
7381
7314
|
var execFileAsync = promisify3(execFile3);
|
|
7382
7315
|
var NEVER_BLOCK = [
|
|
7383
7316
|
/contrast/i,
|
|
@@ -7446,74 +7379,6 @@ function classifyCheckOutput(lintRaw, inspectRaw) {
|
|
|
7446
7379
|
warnings: findings.filter((f) => f.severity === "warning")
|
|
7447
7380
|
};
|
|
7448
7381
|
}
|
|
7449
|
-
var GATE_SECTIONS = ["lint", "runtime", "layout", "motion", "contrast"];
|
|
7450
|
-
function buildCheckArgs(dir, samples) {
|
|
7451
|
-
return ["hyperframes", "check", dir, "--json", "--samples", String(samples), "--at-transitions"];
|
|
7452
|
-
}
|
|
7453
|
-
var PROMOTE_TO_BLOCKING = /GSAP target [^ ]+ not found|no deterministic font mapping/i;
|
|
7454
|
-
function toGateFinding(section, entry) {
|
|
7455
|
-
const f = entry;
|
|
7456
|
-
const code = typeof f.code === "string" ? f.code : "unknown";
|
|
7457
|
-
const message2 = typeof f.message === "string" ? f.message : "";
|
|
7458
|
-
const isError = f.severity === "error" || PROMOTE_TO_BLOCKING.test(message2);
|
|
7459
|
-
const fatal = PROMOTE_TO_BLOCKING.test(message2);
|
|
7460
|
-
return {
|
|
7461
|
-
source: section,
|
|
7462
|
-
code,
|
|
7463
|
-
message: message2,
|
|
7464
|
-
severity: fatal || isError && !isAdvisory(code, message2) ? "blocking" : "warning"
|
|
7465
|
-
};
|
|
7466
|
-
}
|
|
7467
|
-
function classifyGateOutput(raw) {
|
|
7468
|
-
const parsed = parseCheckJson(raw);
|
|
7469
|
-
const findings = GATE_SECTIONS.flatMap((section) => {
|
|
7470
|
-
const block = parsed?.[section];
|
|
7471
|
-
const entries = Array.isArray(block?.findings) ? block.findings : [];
|
|
7472
|
-
return entries.map((entry) => toGateFinding(section, entry));
|
|
7473
|
-
});
|
|
7474
|
-
return {
|
|
7475
|
-
blocking: findings.filter((f) => f.severity === "blocking"),
|
|
7476
|
-
warnings: findings.filter((f) => f.severity === "warning")
|
|
7477
|
-
};
|
|
7478
|
-
}
|
|
7479
|
-
function summariseWarnings(warnings) {
|
|
7480
|
-
const groups = /* @__PURE__ */ new Map();
|
|
7481
|
-
for (const w of warnings) {
|
|
7482
|
-
const key = `${w.source}/${w.code}`;
|
|
7483
|
-
const seen = groups.get(key);
|
|
7484
|
-
if (seen) seen.count += 1;
|
|
7485
|
-
else groups.set(key, { count: 1, message: w.message });
|
|
7486
|
-
}
|
|
7487
|
-
return [...groups.entries()].sort((a, b) => b[1].count - a[1].count).map(([key, g]) => `${g.count}\xD7 [${key}] ${g.message}`);
|
|
7488
|
-
}
|
|
7489
|
-
var FINDING_ADVICE = {
|
|
7490
|
-
sweep_static: "the timeline never advanced, so this renders as a STILL IMAGE while billing like a video \u2014 and every other green verdict in this run is unreliable. Check the composition registers a paused timeline on `window.__timelines[<composition-id>]` and that the tweens target elements that exist.",
|
|
7491
|
-
console_error: "the composition threw in the browser, so whatever that script was driving did not happen.",
|
|
7492
|
-
page_error: "a script failed to evaluate \u2014 animations and any JS-driven layout in this composition did not run.",
|
|
7493
|
-
http_error: "an asset 404ed at render time; it will be missing from the frame, not substituted.",
|
|
7494
|
-
console_warning: "if this names a GSAP target, the element it animates does not exist, so that tween is a no-op and whatever it was meant to reveal never appears. Fix the selector or add the element before rendering."
|
|
7495
|
-
};
|
|
7496
|
-
function explainGateFinding(finding) {
|
|
7497
|
-
const advice = FINDING_ADVICE[finding.code];
|
|
7498
|
-
return advice ? `${finding.message} \u2014 ${advice}` : finding.message;
|
|
7499
|
-
}
|
|
7500
|
-
function condenseFrameDescriptions(markdown) {
|
|
7501
|
-
const lines = [];
|
|
7502
|
-
let frame = null;
|
|
7503
|
-
for (const line of markdown.split("\n")) {
|
|
7504
|
-
const heading = line.match(/^## (.+)$/);
|
|
7505
|
-
if (heading) {
|
|
7506
|
-
frame = heading[1] ?? null;
|
|
7507
|
-
continue;
|
|
7508
|
-
}
|
|
7509
|
-
const text = line.trim();
|
|
7510
|
-
if (frame && text) {
|
|
7511
|
-
lines.push(`${frame}: ${text}`);
|
|
7512
|
-
frame = null;
|
|
7513
|
-
}
|
|
7514
|
-
}
|
|
7515
|
-
return lines;
|
|
7516
|
-
}
|
|
7517
7382
|
function buildLintArgs(dir) {
|
|
7518
7383
|
return ["hyperframes", "lint", dir, "--json"];
|
|
7519
7384
|
}
|
|
@@ -7545,13 +7410,8 @@ async function lintStructuralIssues(dir, timeoutMs) {
|
|
|
7545
7410
|
function buildInspectArgs(dir, samples) {
|
|
7546
7411
|
return ["hyperframes", "inspect", dir, "--json", "--samples", String(samples)];
|
|
7547
7412
|
}
|
|
7548
|
-
function buildSnapshotArgs(dir, frames
|
|
7549
|
-
|
|
7550
|
-
return vision ? [
|
|
7551
|
-
...base,
|
|
7552
|
-
"--describe",
|
|
7553
|
-
"Answer four things about this frame. (1) Is it empty or near-empty? Name every element actually visible. (2) Could what is shown physically happen \u2014 object sizes, human scale, and whether every object has its real-world form (a phone has ONE screen, on its front). Say so plainly if something is impossible. (3) Read out every number, currency symbol and word visible INSIDE the picture \u2014 phone screens, documents, signage \u2014 and say whether any of it contradicts the caption on this frame. (4) Is the caption legible against what is behind it?"
|
|
7554
|
-
] : [...base, "--describe", "false"];
|
|
7413
|
+
function buildSnapshotArgs(dir, frames) {
|
|
7414
|
+
return ["hyperframes", "snapshot", dir, "--frames", String(frames), "--describe", "false"];
|
|
7555
7415
|
}
|
|
7556
7416
|
function usesNestedCompositions(indexHtml) {
|
|
7557
7417
|
const withoutComments = indexHtml.replace(/<!--[\s\S]*?-->/g, "");
|
|
@@ -7580,66 +7440,44 @@ async function runSnapshotSmoke(args, timeoutMs) {
|
|
|
7580
7440
|
return { ok: false, unavailable: false, message: (err.stderr || err.message || "snapshot failed").slice(0, 800) };
|
|
7581
7441
|
}
|
|
7582
7442
|
}
|
|
7583
|
-
async function
|
|
7584
|
-
const { dir, nodeId, ctx, timeoutMs, samples } = opts;
|
|
7585
|
-
const indexHtml = await readFile9(path12.join(dir, "index.html"), "utf-8").catch(() => "");
|
|
7586
|
-
if (!indexHtml || !usesNestedCompositions(indexHtml)) return;
|
|
7587
|
-
const snap = await runSnapshotSmoke(
|
|
7588
|
-
buildSnapshotArgs(dir, Math.min(samples, 3), hasFrameVisionKey()),
|
|
7589
|
-
Math.max(timeoutMs, 12e4)
|
|
7590
|
-
);
|
|
7591
|
-
if (snap.unavailable) {
|
|
7592
|
-
ctx.log(`${nodeId}: hyperframes snapshot unavailable \u2014 skipping nested-composition smoke test`);
|
|
7593
|
-
return;
|
|
7594
|
-
}
|
|
7595
|
-
if (!snap.ok) {
|
|
7596
|
-
throw new Error(
|
|
7597
|
-
`${nodeId}: nested-composition smoke test failed \u2014 an embedded block did not render. Check the host\u2194block id match, that the block's <style>/<script> live inside its <template>, and that it styles #root (not a class).
|
|
7598
|
-
${snap.message}`
|
|
7599
|
-
);
|
|
7600
|
-
}
|
|
7601
|
-
const described = await readFile9(path12.join(dir, "snapshots", "descriptions.md"), "utf-8").catch(() => "");
|
|
7602
|
-
for (const line of condenseFrameDescriptions(described)) {
|
|
7603
|
-
ctx.log(`${nodeId}: frame check \u2014 ${line}`);
|
|
7604
|
-
}
|
|
7605
|
-
ctx.log(`${nodeId}: nested-composition smoke test passed`);
|
|
7606
|
-
}
|
|
7607
|
-
async function runGate(dir, timeoutMs, samples) {
|
|
7608
|
-
const checkRaw = await runOne(buildCheckArgs(dir, samples), timeoutMs);
|
|
7609
|
-
if (checkRaw !== null) return classifyGateOutput(checkRaw);
|
|
7443
|
+
async function runHyperframesCheck(opts) {
|
|
7444
|
+
const { dir, nodeId, ctx, timeoutMs, samples = 5 } = opts;
|
|
7610
7445
|
const [lintRaw, inspectRaw] = await Promise.all([
|
|
7611
7446
|
runOne(buildLintArgs(dir), timeoutMs),
|
|
7612
7447
|
runOne(buildInspectArgs(dir, samples), timeoutMs)
|
|
7613
7448
|
]);
|
|
7614
|
-
if (lintRaw === null && inspectRaw === null)
|
|
7615
|
-
|
|
7616
|
-
}
|
|
7617
|
-
async function runHyperframesCheck(opts) {
|
|
7618
|
-
const { dir, nodeId, ctx, timeoutMs, samples = 5 } = opts;
|
|
7619
|
-
const gate = await runGate(dir, timeoutMs, samples);
|
|
7620
|
-
if (gate === null) {
|
|
7621
|
-
ctx.log(`${nodeId}: hyperframes check/lint/inspect unavailable \u2014 skipping pre-render check`);
|
|
7449
|
+
if (lintRaw === null && inspectRaw === null) {
|
|
7450
|
+
ctx.log(`${nodeId}: hyperframes lint/inspect unavailable \u2014 skipping pre-render check`);
|
|
7622
7451
|
return;
|
|
7623
7452
|
}
|
|
7624
|
-
const { blocking, warnings } =
|
|
7625
|
-
for (const
|
|
7626
|
-
ctx.log(`${nodeId}: hyperframe check warning ${
|
|
7453
|
+
const { blocking, warnings } = classifyCheckOutput(lintRaw ?? "", inspectRaw ?? "");
|
|
7454
|
+
for (const w of warnings) {
|
|
7455
|
+
ctx.log(`${nodeId}: hyperframe check warning [${w.source}/${w.code}] ${w.message}`);
|
|
7627
7456
|
}
|
|
7628
7457
|
if (blocking.length > 0) {
|
|
7629
|
-
const
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
throw new Error(
|
|
7633
|
-
`${nodeId}: pre-render check failed (${blocking.length} blocking, ${seen.size} distinct)
|
|
7634
|
-
${detail}`
|
|
7635
|
-
);
|
|
7458
|
+
const detail = blocking.map((b) => `\u2022 [${b.source}/${b.code}] ${b.message}`).join("\n");
|
|
7459
|
+
throw new Error(`${nodeId}: pre-render check failed (${blocking.length} blocking)
|
|
7460
|
+
${detail}`);
|
|
7636
7461
|
}
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7462
|
+
let indexHtml = "";
|
|
7463
|
+
try {
|
|
7464
|
+
indexHtml = await readFile9(path12.join(dir, "index.html"), "utf-8");
|
|
7465
|
+
} catch {
|
|
7466
|
+
indexHtml = "";
|
|
7467
|
+
}
|
|
7468
|
+
if (indexHtml && usesNestedCompositions(indexHtml)) {
|
|
7469
|
+
const snap = await runSnapshotSmoke(buildSnapshotArgs(dir, Math.min(samples, 3)), Math.max(timeoutMs, 12e4));
|
|
7470
|
+
if (snap.unavailable) {
|
|
7471
|
+
ctx.log(`${nodeId}: hyperframes snapshot unavailable \u2014 skipping nested-composition smoke test`);
|
|
7472
|
+
} else if (!snap.ok) {
|
|
7473
|
+
throw new Error(
|
|
7474
|
+
`${nodeId}: nested-composition smoke test failed \u2014 an embedded block did not render. Check the host\u2194block id match, that the block's <style>/<script> live inside its <template>, and that it styles #root (not a class).
|
|
7475
|
+
${snap.message}`
|
|
7476
|
+
);
|
|
7477
|
+
} else {
|
|
7478
|
+
ctx.log(`${nodeId}: nested-composition smoke test passed`);
|
|
7479
|
+
}
|
|
7641
7480
|
}
|
|
7642
|
-
await runNestedCompositionSmoke({ dir, nodeId, ctx, timeoutMs, samples });
|
|
7643
7481
|
ctx.log(`${nodeId}: pre-render check passed (${warnings.length} warning${warnings.length === 1 ? "" : "s"})`);
|
|
7644
7482
|
}
|
|
7645
7483
|
|
|
@@ -9146,14 +8984,7 @@ async function tryExtractAudio(inputs, ctx) {
|
|
|
9146
8984
|
import { z as z34 } from "zod";
|
|
9147
8985
|
var voiceSelectNode = delegated({
|
|
9148
8986
|
id: "voice_select",
|
|
9149
|
-
|
|
9150
|
-
// and no mime, which every consumer taking the id as an INPUT rejected —
|
|
9151
|
-
// `audio_voice_convert` died on `voice_ref.sha256: expected string, received undefined`.
|
|
9152
|
-
// The backend now uploads it as a real asset like the ranked branch, and the version has
|
|
9153
|
-
// to move with it: the cache key is built from this string, so entries written under
|
|
9154
|
-
// 1.0.0 kept replaying the broken shape long after the fix was deployed. A node whose
|
|
9155
|
-
// OUTPUT shape changes has to bump, not only one whose behaviour does.
|
|
9156
|
-
version: "1.1.0",
|
|
8987
|
+
version: "1.0.0",
|
|
9157
8988
|
category: "audio",
|
|
9158
8989
|
summary: 'Cast an ElevenLabs voice from a natural-language description (e.g. "warm, authoritative female narrator, American accent"). Lists the account\'s voices and ranks them against the brief, emitting the best `voice_id` as a bare-string text asset plus a ranked `candidates` JSON.',
|
|
9159
8990
|
when_to_use: 'Use to turn a voice description (e.g. from a `video_deconstruct` blueprint\'s `voice_description`) into a usable ElevenLabs voice id, then feed it into a `tts` node by wiring `inputs.voice_ref: $ref:<this>.voice_id` and setting `params.voice: "{{voice_ref}}"` \u2014 the engine splices the id in at run time. Review `candidates` (json) to pick a different voice. Optional `gender`/`age`/`accent`/`language` hints sharpen the ranking.',
|
|
@@ -9164,11 +8995,6 @@ var voiceSelectNode = delegated({
|
|
|
9164
8995
|
age: z34.string().optional(),
|
|
9165
8996
|
accent: z34.string().optional(),
|
|
9166
8997
|
language: z34.string().optional(),
|
|
9167
|
-
/**
|
|
9168
|
-
* A voice already chosen — an Avatar's pinned one. Given, nothing is cast: the
|
|
9169
|
-
* ranking is skipped and this id is emitted as-is.
|
|
9170
|
-
*/
|
|
9171
|
-
voice_id: z34.string().min(1).max(120).optional(),
|
|
9172
8998
|
limit: z34.number().int().min(1).max(20).optional()
|
|
9173
8999
|
}).strict(),
|
|
9174
9000
|
outputs: z34.object({ voice_id: TextRef, candidates: JsonRef }).strict(),
|
|
@@ -9331,7 +9157,6 @@ export {
|
|
|
9331
9157
|
describeFailureReason,
|
|
9332
9158
|
AD_FORMAT_PLATFORMS,
|
|
9333
9159
|
platformFormats,
|
|
9334
|
-
frameRealismDirection,
|
|
9335
9160
|
SEEDANCE_DURATIONS,
|
|
9336
9161
|
ELEVENLABS_MAX_MUSIC_LENGTH_MS,
|
|
9337
9162
|
IMAGE_GENERATE_MODELS,
|
|
@@ -9343,13 +9168,10 @@ export {
|
|
|
9343
9168
|
MODEL_REGISTRY,
|
|
9344
9169
|
supportsParam,
|
|
9345
9170
|
DEFAULT_CLIP_DURATION_S,
|
|
9346
|
-
SPOKEN_WORDS_PER_SECOND,
|
|
9347
|
-
spokenWordsIn,
|
|
9348
9171
|
nearestClipDuration,
|
|
9349
9172
|
promptMaxLength,
|
|
9350
9173
|
maxInputSlot,
|
|
9351
9174
|
maxInputReferences,
|
|
9352
|
-
bestSupportedQuality,
|
|
9353
9175
|
nearestSupportedAspectRatio,
|
|
9354
9176
|
nearestSupportedImageSize,
|
|
9355
9177
|
estimateVideoCredits,
|
|
@@ -9390,4 +9212,4 @@ export {
|
|
|
9390
9212
|
defaultRegistry,
|
|
9391
9213
|
createEngineFromEnv
|
|
9392
9214
|
};
|
|
9393
|
-
//# sourceMappingURL=chunk-
|
|
9215
|
+
//# sourceMappingURL=chunk-YFQWCJX4.js.map
|