@koda-sl/baker-cli 0.119.0 → 0.120.0-dev.3bcc79f9c
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 +41 -50
- package/dist/{chunk-MF34WJ7M.js → chunk-OCMOQOIJ.js} +251 -131
- package/dist/chunk-OCMOQOIJ.js.map +1 -0
- package/dist/cli.js +562 -1232
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.d.ts +30 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-MF34WJ7M.js.map +0 -1
|
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
mod
|
|
25
25
|
));
|
|
26
26
|
|
|
27
|
-
//
|
|
27
|
+
// ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
|
|
28
28
|
var require_safe_stable_stringify = __commonJS({
|
|
29
|
-
"
|
|
29
|
+
"../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
|
|
30
30
|
"use strict";
|
|
31
31
|
var { hasOwnProperty } = Object.prototype;
|
|
32
32
|
var stringify = configure2();
|
|
@@ -159,9 +159,9 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
159
159
|
}
|
|
160
160
|
if (value) {
|
|
161
161
|
return (value2) => {
|
|
162
|
-
let
|
|
163
|
-
if (typeof value2 !== "function")
|
|
164
|
-
throw new Error(
|
|
162
|
+
let message2 = `Object can not safely be stringified. Received type ${typeof value2}`;
|
|
163
|
+
if (typeof value2 !== "function") message2 += ` (${value2.toString()})`;
|
|
164
|
+
throw new Error(message2);
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
167
|
}
|
|
@@ -673,6 +673,9 @@ var HttpClient = class {
|
|
|
673
673
|
async postJson(path16, body, signal) {
|
|
674
674
|
return await this.requestJson("POST", path16, body, signal);
|
|
675
675
|
}
|
|
676
|
+
async putJson(path16, body, signal) {
|
|
677
|
+
return await this.requestJson("PUT", path16, body, signal);
|
|
678
|
+
}
|
|
676
679
|
async getJson(path16, signal) {
|
|
677
680
|
return await this.requestJson("GET", path16, void 0, signal);
|
|
678
681
|
}
|
|
@@ -700,8 +703,8 @@ var HttpClient = class {
|
|
|
700
703
|
try {
|
|
701
704
|
const res = await this.fetchFn(url, {
|
|
702
705
|
method,
|
|
703
|
-
headers: method === "
|
|
704
|
-
body: method === "
|
|
706
|
+
headers: method === "GET" ? { Authorization: `Bearer ${this.apiKey}` } : { "Content-Type": "application/json", Authorization: `Bearer ${this.apiKey}` },
|
|
707
|
+
body: method === "GET" ? void 0 : JSON.stringify(body),
|
|
705
708
|
signal: controller.signal
|
|
706
709
|
});
|
|
707
710
|
if (res.ok) return { kind: "value", value: await res.json() };
|
|
@@ -738,33 +741,33 @@ async function parseErrorBody(res) {
|
|
|
738
741
|
const errObj = body.error ?? {};
|
|
739
742
|
return classifyHttpError(res.status, errObj, errObj.message ?? `HTTP ${res.status}`);
|
|
740
743
|
}
|
|
741
|
-
function classifyHttpError(status, errObj,
|
|
744
|
+
function classifyHttpError(status, errObj, message2) {
|
|
742
745
|
if (errObj.code === CONTENT_POLICY_CODE) {
|
|
743
|
-
return { kind: "content_policy", status, provider: errObj.provider, message };
|
|
746
|
+
return { kind: "content_policy", status, provider: errObj.provider, message: message2 };
|
|
744
747
|
}
|
|
745
748
|
if (status === 401 || status === 403) {
|
|
746
|
-
return { kind: "unauthorized", status, message };
|
|
749
|
+
return { kind: "unauthorized", status, message: message2 };
|
|
747
750
|
}
|
|
748
751
|
if (status === 400 || status === 422) {
|
|
749
|
-
return { kind: "validation", status, message, details: errObj.details };
|
|
752
|
+
return { kind: "validation", status, message: message2, details: errObj.details };
|
|
750
753
|
}
|
|
751
754
|
if (status === 502 || status === 504) {
|
|
752
755
|
if (errObj.code === "provider_timeout" || status === 504) {
|
|
753
|
-
return { kind: "timeout", provider: errObj.provider, message };
|
|
756
|
+
return { kind: "timeout", provider: errObj.provider, message: message2 };
|
|
754
757
|
}
|
|
755
758
|
return {
|
|
756
759
|
kind: "provider",
|
|
757
760
|
status,
|
|
758
761
|
provider: errObj.provider,
|
|
759
762
|
code: errObj.code ?? "provider_error",
|
|
760
|
-
message,
|
|
763
|
+
message: message2,
|
|
761
764
|
retryable: errObj.retryable ?? true
|
|
762
765
|
};
|
|
763
766
|
}
|
|
764
767
|
if (status >= 500 || status === 429) {
|
|
765
|
-
return { kind: "server", status, message };
|
|
768
|
+
return { kind: "server", status, message: message2 };
|
|
766
769
|
}
|
|
767
|
-
return { kind: "validation", status, message, details: errObj.details };
|
|
770
|
+
return { kind: "validation", status, message: message2, details: errObj.details };
|
|
768
771
|
}
|
|
769
772
|
function backoffMs(attempt) {
|
|
770
773
|
return 1e3 * 2 ** attempt;
|
|
@@ -835,6 +838,27 @@ var BackendClient = class {
|
|
|
835
838
|
signal
|
|
836
839
|
);
|
|
837
840
|
}
|
|
841
|
+
/** Remote cache lookup. A miss (404) — or an old backend without the route — returns null. */
|
|
842
|
+
async getCacheEntry(cacheKey, signal) {
|
|
843
|
+
try {
|
|
844
|
+
const res = await this.http.getJson(`/api/canvas/cache/${encodeURIComponent(cacheKey)}`, signal);
|
|
845
|
+
return res.entry;
|
|
846
|
+
} catch (e) {
|
|
847
|
+
if (e instanceof BackendHttpError && "status" in e.detail && e.detail.status === 404) return null;
|
|
848
|
+
throw e;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async putCacheEntry(entry, signal) {
|
|
852
|
+
await this.http.putJson(
|
|
853
|
+
`/api/canvas/cache/${encodeURIComponent(entry.cacheKey)}`,
|
|
854
|
+
entry,
|
|
855
|
+
signal
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
/** Durable run-history record — POST /api/canvas/runs (idempotent server-side on runId). */
|
|
859
|
+
async recordRun(payload, signal) {
|
|
860
|
+
await this.http.postJson("/api/canvas/runs", payload, signal);
|
|
861
|
+
}
|
|
838
862
|
getArtifact(kind, name, version, signal) {
|
|
839
863
|
const path16 = version ? `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}`;
|
|
840
864
|
return this.http.getJson(path16, signal);
|
|
@@ -858,14 +882,17 @@ function requireCredentialsFromEnv(env = process.env) {
|
|
|
858
882
|
}
|
|
859
883
|
return c;
|
|
860
884
|
}
|
|
885
|
+
function remoteCacheEnabledFromEnv(env = process.env) {
|
|
886
|
+
return env.BAKER_CANVAS_REMOTE_CACHE !== "off";
|
|
887
|
+
}
|
|
861
888
|
|
|
862
889
|
// src/engine/engine/errors.ts
|
|
863
890
|
function isBlocking(issue) {
|
|
864
891
|
return issue.severity !== "warning";
|
|
865
892
|
}
|
|
866
893
|
var CanvasError = class extends Error {
|
|
867
|
-
constructor(
|
|
868
|
-
super(
|
|
894
|
+
constructor(message2) {
|
|
895
|
+
super(message2);
|
|
869
896
|
this.name = "CanvasError";
|
|
870
897
|
}
|
|
871
898
|
};
|
|
@@ -922,7 +949,7 @@ function describeCause(c) {
|
|
|
922
949
|
}
|
|
923
950
|
}
|
|
924
951
|
|
|
925
|
-
//
|
|
952
|
+
// ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
|
|
926
953
|
var import__ = __toESM(require_safe_stable_stringify(), 1);
|
|
927
954
|
var configure = import__.default.configure;
|
|
928
955
|
var wrapper_default = import__.default;
|
|
@@ -1583,6 +1610,158 @@ function encodeRandom() {
|
|
|
1583
1610
|
return out;
|
|
1584
1611
|
}
|
|
1585
1612
|
|
|
1613
|
+
// src/engine/storage/remote-cache-store.ts
|
|
1614
|
+
var CANVAS_ASSETS_URL_SEGMENT = "/canvas-assets/";
|
|
1615
|
+
function isPersistedAssetRef(ref) {
|
|
1616
|
+
return typeof ref.url === "string" && ref.url.includes(`${CANVAS_ASSETS_URL_SEGMENT}${ref.sha256}`);
|
|
1617
|
+
}
|
|
1618
|
+
function isAssetRefLike(value) {
|
|
1619
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && typeof value.sha256 === "string" && typeof value.mime === "string";
|
|
1620
|
+
}
|
|
1621
|
+
function collectAssetRefLikes(value, out = []) {
|
|
1622
|
+
if (Array.isArray(value)) {
|
|
1623
|
+
for (const item of value) collectAssetRefLikes(item, out);
|
|
1624
|
+
return out;
|
|
1625
|
+
}
|
|
1626
|
+
if (typeof value !== "object" || value === null) return out;
|
|
1627
|
+
if (isAssetRefLike(value)) {
|
|
1628
|
+
out.push(value);
|
|
1629
|
+
}
|
|
1630
|
+
for (const item of Object.values(value)) collectAssetRefLikes(item, out);
|
|
1631
|
+
return out;
|
|
1632
|
+
}
|
|
1633
|
+
function entryFullyPersisted(entry) {
|
|
1634
|
+
return collectAssetRefLikes(entry.outputs).every((ref) => isPersistedAssetRef(ref));
|
|
1635
|
+
}
|
|
1636
|
+
function stripLocalFields(entry) {
|
|
1637
|
+
const clone = JSON.parse(JSON.stringify(entry));
|
|
1638
|
+
for (const ref of collectAssetRefLikes(clone.outputs)) {
|
|
1639
|
+
delete ref.path;
|
|
1640
|
+
delete ref.bytes;
|
|
1641
|
+
}
|
|
1642
|
+
return clone;
|
|
1643
|
+
}
|
|
1644
|
+
var RemoteCacheStore = class {
|
|
1645
|
+
client;
|
|
1646
|
+
log;
|
|
1647
|
+
constructor(client, log) {
|
|
1648
|
+
this.client = client;
|
|
1649
|
+
this.log = log ?? (() => void 0);
|
|
1650
|
+
}
|
|
1651
|
+
async get(cacheKey) {
|
|
1652
|
+
return await this.client.getCacheEntry(cacheKey);
|
|
1653
|
+
}
|
|
1654
|
+
async put(entry) {
|
|
1655
|
+
if (!entryFullyPersisted(entry)) {
|
|
1656
|
+
this.log(`[cache ] ${entry.cacheKey.slice(0, 12)}\u2026 has local-only assets, kept local`);
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
const stripped = stripLocalFields(entry);
|
|
1660
|
+
if (stripped.refs.length > MAX_REMOTE_REFS) {
|
|
1661
|
+
stripped.refs = stripped.refs.slice(0, MAX_REMOTE_REFS);
|
|
1662
|
+
}
|
|
1663
|
+
await this.client.putCacheEntry(stripped);
|
|
1664
|
+
}
|
|
1665
|
+
};
|
|
1666
|
+
var MAX_REMOTE_REFS = 512;
|
|
1667
|
+
var LayeredCacheStore = class {
|
|
1668
|
+
rootDir;
|
|
1669
|
+
local;
|
|
1670
|
+
remote;
|
|
1671
|
+
assets;
|
|
1672
|
+
log;
|
|
1673
|
+
constructor(opts) {
|
|
1674
|
+
this.local = opts.local;
|
|
1675
|
+
this.remote = opts.remote;
|
|
1676
|
+
this.assets = opts.assets;
|
|
1677
|
+
this.rootDir = opts.local.rootDir;
|
|
1678
|
+
this.log = opts.log ?? (() => void 0);
|
|
1679
|
+
}
|
|
1680
|
+
async get(cacheKey) {
|
|
1681
|
+
const localHit = await this.local.get(cacheKey);
|
|
1682
|
+
if (localHit) return localHit;
|
|
1683
|
+
let remoteEntry;
|
|
1684
|
+
try {
|
|
1685
|
+
remoteEntry = await this.remote.get(cacheKey);
|
|
1686
|
+
} catch (e) {
|
|
1687
|
+
this.log(`[cache ] remote lookup failed (${message(e)}) \u2014 treating as miss`);
|
|
1688
|
+
return null;
|
|
1689
|
+
}
|
|
1690
|
+
if (!remoteEntry) return null;
|
|
1691
|
+
let rehydrated;
|
|
1692
|
+
try {
|
|
1693
|
+
rehydrated = await this.rehydrate(remoteEntry);
|
|
1694
|
+
} catch (e) {
|
|
1695
|
+
this.log(`[cache ] ${cacheKey.slice(0, 12)}\u2026 rehydration failed (${message(e)}) \u2014 treating as miss`);
|
|
1696
|
+
return null;
|
|
1697
|
+
}
|
|
1698
|
+
await this.local.put(rehydrated);
|
|
1699
|
+
return rehydrated;
|
|
1700
|
+
}
|
|
1701
|
+
async put(entry) {
|
|
1702
|
+
await this.local.put(entry);
|
|
1703
|
+
try {
|
|
1704
|
+
await this.remote.put(entry);
|
|
1705
|
+
} catch (e) {
|
|
1706
|
+
this.log(`[cache ] remote write failed (${message(e)}) \u2014 entry kept local`);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Download every referenced asset into the local content-addressed store
|
|
1711
|
+
* (sha-verified) and stamp fresh local paths. Any ref that cannot be
|
|
1712
|
+
* rehydrated fails the WHOLE entry — a partially-hydrated cache hit would
|
|
1713
|
+
* crash materialization later with a far less actionable error.
|
|
1714
|
+
*/
|
|
1715
|
+
async rehydrate(entry) {
|
|
1716
|
+
const clone = JSON.parse(JSON.stringify(entry));
|
|
1717
|
+
for (const ref of collectAssetRefLikes(clone.outputs)) {
|
|
1718
|
+
if (!isPersistedAssetRef(ref)) {
|
|
1719
|
+
throw new Error(`ref ${ref.sha256.slice(0, 12)}\u2026 has no persisted url`);
|
|
1720
|
+
}
|
|
1721
|
+
const ingested = await this.assets.ingestRemote({
|
|
1722
|
+
kind: typeof ref.kind === "string" ? ref.kind : "json",
|
|
1723
|
+
url: ref.url,
|
|
1724
|
+
sha256: ref.sha256,
|
|
1725
|
+
mime: ref.mime,
|
|
1726
|
+
metadata: ref.metadata ?? void 0
|
|
1727
|
+
});
|
|
1728
|
+
ref.path = ingested.path;
|
|
1729
|
+
}
|
|
1730
|
+
return clone;
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
function message(e) {
|
|
1734
|
+
return e instanceof Error ? e.message : String(e);
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
// src/engine/nodes/remote/upload.ts
|
|
1738
|
+
async function presignAndPut(args) {
|
|
1739
|
+
const { putUrl, publicUrl } = await args.ctx.client.presignAssetUpload(args.sha256, args.mime, args.ctx.signal);
|
|
1740
|
+
const putRes = await fetch(putUrl, {
|
|
1741
|
+
method: "PUT",
|
|
1742
|
+
body: new Uint8Array(args.bytes),
|
|
1743
|
+
headers: { "Content-Type": args.mime },
|
|
1744
|
+
signal: args.ctx.signal
|
|
1745
|
+
});
|
|
1746
|
+
if (!putRes.ok) {
|
|
1747
|
+
throw new Error(`upload: presigned PUT failed ${putRes.status} ${putRes.statusText}`);
|
|
1748
|
+
}
|
|
1749
|
+
return publicUrl;
|
|
1750
|
+
}
|
|
1751
|
+
async function ensureUploaded(ref, ctx) {
|
|
1752
|
+
if (ref.url) return ref;
|
|
1753
|
+
const bytes = await ctx.assets.readBytes(ref.sha256, ref.mime);
|
|
1754
|
+
const url = await presignAndPut({ bytes, sha256: ref.sha256, mime: ref.mime, ctx });
|
|
1755
|
+
return { ...ref, url };
|
|
1756
|
+
}
|
|
1757
|
+
async function persistOutputAssetUrls(outputs, ctx) {
|
|
1758
|
+
for (const ref of collectAssetRefLikes(outputs)) {
|
|
1759
|
+
if (isPersistedAssetRef(ref)) continue;
|
|
1760
|
+
const bytes = await ctx.assets.readBytes(ref.sha256, ref.mime);
|
|
1761
|
+
ref.url = await presignAndPut({ bytes, sha256: ref.sha256, mime: ref.mime, ctx });
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1586
1765
|
// src/engine/schema/canvas.ts
|
|
1587
1766
|
import { z } from "zod";
|
|
1588
1767
|
var REF_PREFIX = "$ref:";
|
|
@@ -1644,11 +1823,7 @@ var VideoMeta = z.object({
|
|
|
1644
1823
|
// Advisory: the scene's visual length vs the estimated spoken length, so
|
|
1645
1824
|
// a reviewer can see a native line that may run past its cut. Not gated.
|
|
1646
1825
|
scene_s: z.number().optional(),
|
|
1647
|
-
est_speech_s: z.number().optional()
|
|
1648
|
-
// Word count of the line est_speech_s was measured for. Together they carry
|
|
1649
|
-
// the speaker's OBSERVED pace (from the deconstruct's word timings), so the
|
|
1650
|
-
// overrun check budgets re-authored lines at the real rate, not a wps guess.
|
|
1651
|
-
speech_words: z.number().optional()
|
|
1826
|
+
est_speech_s: z.number().optional()
|
|
1652
1827
|
}),
|
|
1653
1828
|
z.object({ scene: z.number(), lipsync_node: z.string() })
|
|
1654
1829
|
])
|
|
@@ -2178,9 +2353,7 @@ var STAGE_CODES = {
|
|
|
2178
2353
|
SPEECH_OVERRUN: "VIDEO_SPEECH_OVERRUN",
|
|
2179
2354
|
ASPECT_MISMATCH: "VIDEO_ASPECT_MISMATCH",
|
|
2180
2355
|
REFERENCE_MISSING: "VIDEO_REFERENCE_MISSING",
|
|
2181
|
-
SPAN_EXCEEDS_MODEL: "VIDEO_SPAN_EXCEEDS_MODEL"
|
|
2182
|
-
UI_IN_PROMPT: "VIDEO_UI_IN_PROMPT",
|
|
2183
|
-
BRANDMARK_IN_PROMPT: "VIDEO_BRANDMARK_IN_PROMPT"
|
|
2356
|
+
SPAN_EXCEEDS_MODEL: "VIDEO_SPAN_EXCEEDS_MODEL"
|
|
2184
2357
|
};
|
|
2185
2358
|
var SPAN_MODEL_SLACK_S = 0.25;
|
|
2186
2359
|
var VIDEO_TIME_SLACK_S = 0.75;
|
|
@@ -2559,8 +2732,6 @@ function checkVideoInvariants(ctx) {
|
|
|
2559
2732
|
}
|
|
2560
2733
|
checkSpeechOverrun(ctx, meta.talking_scenes);
|
|
2561
2734
|
checkAspectConsistency(ctx);
|
|
2562
|
-
checkUiInPrompt(ctx);
|
|
2563
|
-
checkBrandmarkInPrompt(ctx);
|
|
2564
2735
|
checkReferenceCompleteness(ctx, meta);
|
|
2565
2736
|
checkClipSpanFitsModel(ctx, meta);
|
|
2566
2737
|
}
|
|
@@ -2590,30 +2761,18 @@ function keywordTokens(text) {
|
|
|
2590
2761
|
if (!text) return [];
|
|
2591
2762
|
return text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 3 && !KEYWORD_STOPWORDS.has(t));
|
|
2592
2763
|
}
|
|
2593
|
-
function elementMentionKeywords(el) {
|
|
2594
|
-
const typeWords = ELEMENT_TYPE_KEYWORDS[el.type.toLowerCase()] ?? [];
|
|
2595
|
-
return [.../* @__PURE__ */ new Set([...typeWords, ...keywordTokens(el.label), ...keywordTokens(el.description)])];
|
|
2596
|
-
}
|
|
2597
2764
|
function keywordsForElement(el) {
|
|
2598
|
-
|
|
2765
|
+
const type = el.type.toLowerCase();
|
|
2766
|
+
const typeWords = ELEMENT_TYPE_KEYWORDS[type] ?? [];
|
|
2767
|
+
return [.../* @__PURE__ */ new Set([...typeWords, ...keywordTokens(el.label), ...keywordTokens(el.description)])];
|
|
2599
2768
|
}
|
|
2600
2769
|
function containsWord(text, word) {
|
|
2601
2770
|
const esc = word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2602
2771
|
return new RegExp(`\\b${esc}\\b`, "i").test(text);
|
|
2603
2772
|
}
|
|
2604
|
-
var FRAME_DESCRIPTION_START = "FRAME DESCRIPTION (this frame's editable prompt):";
|
|
2605
|
-
var FRAME_DESCRIPTION_END = "Render exactly what the FRAME DESCRIPTION";
|
|
2606
|
-
function frameDescriptionOf(prompt) {
|
|
2607
|
-
const i = prompt.indexOf(FRAME_DESCRIPTION_START);
|
|
2608
|
-
if (i < 0) return prompt;
|
|
2609
|
-
const rest = prompt.slice(i + FRAME_DESCRIPTION_START.length);
|
|
2610
|
-
const j = rest.indexOf(FRAME_DESCRIPTION_END);
|
|
2611
|
-
return j < 0 ? rest : rest.slice(0, j);
|
|
2612
|
-
}
|
|
2613
2773
|
function checkFrameReferences(ctx, node, index, keyworded) {
|
|
2614
|
-
const
|
|
2615
|
-
if (typeof
|
|
2616
|
-
const prompt = frameDescriptionOf(rawPrompt);
|
|
2774
|
+
const prompt = node.params?.prompt;
|
|
2775
|
+
if (typeof prompt !== "string" || prompt.length === 0) return;
|
|
2617
2776
|
const inputsBlob = JSON.stringify(node.inputs ?? {});
|
|
2618
2777
|
for (const { el, keywords } of keyworded) {
|
|
2619
2778
|
if (inputsBlob.includes(el.ref)) continue;
|
|
@@ -2663,24 +2822,13 @@ function checkClipSpanFitsModel(ctx, meta) {
|
|
|
2663
2822
|
});
|
|
2664
2823
|
}
|
|
2665
2824
|
}
|
|
2666
|
-
|
|
2667
|
-
var OBSERVED_WPS_MAX = 6;
|
|
2668
|
-
function secondsPerWord(stamped) {
|
|
2669
|
-
const est = stamped?.est_speech_s;
|
|
2670
|
-
const words = stamped?.speech_words;
|
|
2671
|
-
if (est && words && est > 0 && words > 0) {
|
|
2672
|
-
const wps = words / est;
|
|
2673
|
-
if (wps >= OBSERVED_WPS_MIN && wps <= OBSERVED_WPS_MAX) return est / words;
|
|
2674
|
-
}
|
|
2675
|
-
return 1 / SPEECH_WORDS_PER_SECOND;
|
|
2676
|
-
}
|
|
2677
|
-
function speechOverrunOf(node, secPerWord) {
|
|
2825
|
+
function speechOverrunOf(node) {
|
|
2678
2826
|
const params = node.params;
|
|
2679
2827
|
if (params?.generate_audio !== true) return null;
|
|
2680
2828
|
const line = nativeDialogueOf(params.prompt);
|
|
2681
2829
|
const duration = typeof params.duration === "number" ? params.duration : void 0;
|
|
2682
2830
|
if (!line || !duration) return null;
|
|
2683
|
-
const estSpeechS = line.split(/\s+/).filter(Boolean).length
|
|
2831
|
+
const estSpeechS = line.split(/\s+/).filter(Boolean).length / SPEECH_WORDS_PER_SECOND;
|
|
2684
2832
|
return estSpeechS > duration * SPEECH_OVERRUN_RATIO ? { estSpeechS, duration } : null;
|
|
2685
2833
|
}
|
|
2686
2834
|
function checkSpeechOverrun(ctx, talkingScenes) {
|
|
@@ -2689,7 +2837,7 @@ function checkSpeechOverrun(ctx, talkingScenes) {
|
|
|
2689
2837
|
const nativeClipRe = new RegExp(`^s${entry.scene}(_r\\d+)?_clip$`);
|
|
2690
2838
|
for (const n of ctx.canvas.nodes) {
|
|
2691
2839
|
if (!nativeClipRe.test(n.id) || n.type !== "video_generate") continue;
|
|
2692
|
-
const overrun = speechOverrunOf(n
|
|
2840
|
+
const overrun = speechOverrunOf(n);
|
|
2693
2841
|
if (!overrun) continue;
|
|
2694
2842
|
ctx.issues.push({
|
|
2695
2843
|
path: `nodes[${ctx.idToIndex.get(n.id) ?? -1}].params.prompt`,
|
|
@@ -2699,38 +2847,6 @@ function checkSpeechOverrun(ctx, talkingScenes) {
|
|
|
2699
2847
|
}
|
|
2700
2848
|
}
|
|
2701
2849
|
}
|
|
2702
|
-
var UI_IN_PROMPT_RE = /\bscreen[- ]?(?:recording|capture|grab|share)\b|\bapp (?:interface|screen)\b|\bphone screen overlay\b/i;
|
|
2703
|
-
function checkUiInPrompt(ctx) {
|
|
2704
|
-
for (const n of ctx.canvas.nodes) {
|
|
2705
|
-
if (n.type !== "video_generate") continue;
|
|
2706
|
-
const prompt = n.params?.prompt;
|
|
2707
|
-
if (typeof prompt !== "string" || !UI_IN_PROMPT_RE.test(prompt)) continue;
|
|
2708
|
-
ctx.issues.push({
|
|
2709
|
-
path: `nodes[${ctx.idToIndex.get(n.id) ?? -1}].params.prompt`,
|
|
2710
|
-
code: STAGE_CODES.UI_IN_PROMPT,
|
|
2711
|
-
severity: "warning",
|
|
2712
|
-
message: `"${n.id}" asks the video model to render a screen/UI surface \u2014 generative video garbles UI text and chrome. Composite the real screen on the overlay layer (screenshot / brand HTML) and keep this prompt to the background plate`,
|
|
2713
|
-
node_id: n.id,
|
|
2714
|
-
node_type: "video_generate"
|
|
2715
|
-
});
|
|
2716
|
-
}
|
|
2717
|
-
}
|
|
2718
|
-
var BRANDMARK_IN_PROMPT_RE = /\b(?:logo|wordmark) (?:overlay|animation|sting|card|reveal)\b|\b(?:google|facebook|instagram|tiktok|youtube|amazon|apple|microsoft|whatsapp|netflix|spotify|excel|trustpilot) (?:logo|wordmark|branding)\b/i;
|
|
2719
|
-
function checkBrandmarkInPrompt(ctx) {
|
|
2720
|
-
for (const n of ctx.canvas.nodes) {
|
|
2721
|
-
if (n.type !== "video_generate" && n.type !== "image_generate") continue;
|
|
2722
|
-
const prompt = n.params?.prompt;
|
|
2723
|
-
if (typeof prompt !== "string" || !BRANDMARK_IN_PROMPT_RE.test(prompt)) continue;
|
|
2724
|
-
ctx.issues.push({
|
|
2725
|
-
path: `nodes[${ctx.idToIndex.get(n.id) ?? -1}].params.prompt`,
|
|
2726
|
-
code: STAGE_CODES.BRANDMARK_IN_PROMPT,
|
|
2727
|
-
severity: "warning",
|
|
2728
|
-
message: `"${n.id}" asks the model to render a brand logo/wordmark \u2014 generation garbles marks and third-party logos carry IP exposure. Source the real mark (baker images logo <domain>) and composite it on the overlay layer`,
|
|
2729
|
-
node_id: n.id,
|
|
2730
|
-
node_type: n.type
|
|
2731
|
-
});
|
|
2732
|
-
}
|
|
2733
|
-
}
|
|
2734
2850
|
function checkAspectConsistency(ctx) {
|
|
2735
2851
|
const clips = ctx.canvas.nodes.filter((n) => n.type === "video_generate");
|
|
2736
2852
|
if (clips.length < 2) return;
|
|
@@ -2862,6 +2978,7 @@ var Engine = class {
|
|
|
2862
2978
|
cache;
|
|
2863
2979
|
outputsDir;
|
|
2864
2980
|
log;
|
|
2981
|
+
persistAssets;
|
|
2865
2982
|
constructor(opts) {
|
|
2866
2983
|
this.registry = opts.registry;
|
|
2867
2984
|
this.client = opts.client;
|
|
@@ -2869,6 +2986,7 @@ var Engine = class {
|
|
|
2869
2986
|
this.cache = opts.cache;
|
|
2870
2987
|
this.outputsDir = opts.outputsDir;
|
|
2871
2988
|
this.log = opts.log ?? (() => void 0);
|
|
2989
|
+
this.persistAssets = opts.persistAssets ?? false;
|
|
2872
2990
|
}
|
|
2873
2991
|
validate(canvas) {
|
|
2874
2992
|
return validateCanvas(canvas, this.registry);
|
|
@@ -2915,7 +3033,7 @@ var Engine = class {
|
|
|
2915
3033
|
`[done ] ${stats.cached_nodes}/${stats.total_nodes} cached, ${stats.total_credits} credits, ${stats.duration_ms}ms`
|
|
2916
3034
|
);
|
|
2917
3035
|
this.log(`outputs in: ${writer.runDir}`);
|
|
2918
|
-
return { run_id: runId, output, outputs_by_node: outputs, stats, outputs_dir: writer.runDir };
|
|
3036
|
+
return { run_id: runId, output, outputs_by_node: outputs, stats, outputs_dir: writer.runDir, node_runs: nodeRuns };
|
|
2919
3037
|
}
|
|
2920
3038
|
async runLayers(canvas, outputs, runId, writer, opts, counters, nodeRuns) {
|
|
2921
3039
|
const layers = topologicalLayers(this.pruneToOutput(canvas, buildGraph(canvas)));
|
|
@@ -3012,6 +3130,14 @@ var Engine = class {
|
|
|
3012
3130
|
const credits = def.cost ? def.cost({ params: parsedParams }).credits : 0;
|
|
3013
3131
|
const outputsObj = result;
|
|
3014
3132
|
outputs[node.id] = outputsObj;
|
|
3133
|
+
if (this.persistAssets) {
|
|
3134
|
+
try {
|
|
3135
|
+
await persistOutputAssetUrls(outputsObj, ctx);
|
|
3136
|
+
} catch (e) {
|
|
3137
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
3138
|
+
this.log(`[warn ] ${node.id}: asset persistence failed (${msg}) \u2014 outputs stay local-only`);
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3015
3141
|
if (policy === "read_write") {
|
|
3016
3142
|
await this.cache.put({
|
|
3017
3143
|
cacheKey: prepared.cacheKey,
|
|
@@ -3330,27 +3456,6 @@ var FontRef = BaseAssetRef.extend({
|
|
|
3330
3456
|
});
|
|
3331
3457
|
var AssetRef = z4.discriminatedUnion("kind", [ImageRef, VideoRef, AudioRef, JsonRef, TextRef, FontRef]);
|
|
3332
3458
|
|
|
3333
|
-
// src/engine/nodes/remote/upload.ts
|
|
3334
|
-
async function presignAndPut(args) {
|
|
3335
|
-
const { putUrl, publicUrl } = await args.ctx.client.presignAssetUpload(args.sha256, args.mime, args.ctx.signal);
|
|
3336
|
-
const putRes = await fetch(putUrl, {
|
|
3337
|
-
method: "PUT",
|
|
3338
|
-
body: new Uint8Array(args.bytes),
|
|
3339
|
-
headers: { "Content-Type": args.mime },
|
|
3340
|
-
signal: args.ctx.signal
|
|
3341
|
-
});
|
|
3342
|
-
if (!putRes.ok) {
|
|
3343
|
-
throw new Error(`upload: presigned PUT failed ${putRes.status} ${putRes.statusText}`);
|
|
3344
|
-
}
|
|
3345
|
-
return publicUrl;
|
|
3346
|
-
}
|
|
3347
|
-
async function ensureUploaded(ref, ctx) {
|
|
3348
|
-
if (ref.url) return ref;
|
|
3349
|
-
const bytes = await ctx.assets.readBytes(ref.sha256, ref.mime);
|
|
3350
|
-
const url = await presignAndPut({ bytes, sha256: ref.sha256, mime: ref.mime, ctx });
|
|
3351
|
-
return { ...ref, url };
|
|
3352
|
-
}
|
|
3353
|
-
|
|
3354
3459
|
// src/engine/nodes/remote/delegate.ts
|
|
3355
3460
|
function delegated(spec) {
|
|
3356
3461
|
return {
|
|
@@ -3745,10 +3850,10 @@ function inferKindFromMime(mime) {
|
|
|
3745
3850
|
if (mime.startsWith("font/")) return "font";
|
|
3746
3851
|
return null;
|
|
3747
3852
|
}
|
|
3748
|
-
function localExecError(ctx,
|
|
3853
|
+
function localExecError(ctx, message2) {
|
|
3749
3854
|
return new NodeExecutionError(ctx.nodeId, ctx.nodeType, {
|
|
3750
3855
|
kind: "local",
|
|
3751
|
-
cause: new Error(`ingest: ${
|
|
3856
|
+
cause: new Error(`ingest: ${message2}`)
|
|
3752
3857
|
});
|
|
3753
3858
|
}
|
|
3754
3859
|
async function execLocalFile(params, ctx) {
|
|
@@ -4415,7 +4520,7 @@ async function refToUrl(ref) {
|
|
|
4415
4520
|
return `data:${ref.mime};base64,${bytes.toString("base64")}`;
|
|
4416
4521
|
}
|
|
4417
4522
|
var ASSET_KINDS = /* @__PURE__ */ new Set(["image", "video", "audio", "json", "text", "font"]);
|
|
4418
|
-
function
|
|
4523
|
+
function isAssetRefLike2(value) {
|
|
4419
4524
|
if (!value || typeof value !== "object") return false;
|
|
4420
4525
|
const v = value;
|
|
4421
4526
|
return typeof v.kind === "string" && ASSET_KINDS.has(v.kind) && typeof v.mime === "string" && typeof v.sha256 === "string" && (typeof v.url === "string" || typeof v.path === "string");
|
|
@@ -4787,8 +4892,8 @@ var NEVER_BLOCK = [
|
|
|
4787
4892
|
/text[_-]?occluded/i
|
|
4788
4893
|
];
|
|
4789
4894
|
var UNAVAILABLE = /unknown command|command not found|not found|Did you mean|Unknown argument|ENOENT/i;
|
|
4790
|
-
function isAdvisory(code,
|
|
4791
|
-
const hay = `${code} ${
|
|
4895
|
+
function isAdvisory(code, message2) {
|
|
4896
|
+
const hay = `${code} ${message2}`;
|
|
4792
4897
|
return NEVER_BLOCK.some((re) => re.test(hay));
|
|
4793
4898
|
}
|
|
4794
4899
|
function parseCheckJson(raw) {
|
|
@@ -4816,10 +4921,10 @@ function classifyLint(json) {
|
|
|
4816
4921
|
for (const f of findings) {
|
|
4817
4922
|
const rec = f;
|
|
4818
4923
|
const code = String(rec?.code ?? "");
|
|
4819
|
-
const
|
|
4924
|
+
const message2 = String(rec?.message ?? "");
|
|
4820
4925
|
const severity = String(rec?.severity ?? "info");
|
|
4821
|
-
const blocking = severity === "error" && !isAdvisory(code,
|
|
4822
|
-
out.push({ source: "lint", code, message, severity: blocking ? "blocking" : "warning" });
|
|
4926
|
+
const blocking = severity === "error" && !isAdvisory(code, message2);
|
|
4927
|
+
out.push({ source: "lint", code, message: message2, severity: blocking ? "blocking" : "warning" });
|
|
4823
4928
|
}
|
|
4824
4929
|
return out;
|
|
4825
4930
|
}
|
|
@@ -4831,9 +4936,9 @@ function classifyInspect(json) {
|
|
|
4831
4936
|
for (const iss of issues) {
|
|
4832
4937
|
const rec = iss;
|
|
4833
4938
|
const code = String(rec?.code ?? rec?.type ?? "overflow");
|
|
4834
|
-
const
|
|
4939
|
+
const message2 = String(rec?.message ?? rec?.detail ?? JSON.stringify(iss));
|
|
4835
4940
|
const severity = rec?.severity ? String(rec.severity) : obj?.ok === false ? "error" : "warning";
|
|
4836
|
-
out.push({ source: "inspect", code, message, severity: severity === "error" ? "blocking" : "warning" });
|
|
4941
|
+
out.push({ source: "inspect", code, message: message2, severity: severity === "error" ? "blocking" : "warning" });
|
|
4837
4942
|
}
|
|
4838
4943
|
return out;
|
|
4839
4944
|
}
|
|
@@ -5278,7 +5383,7 @@ async function buildSubstitutionValues(compositionParams, meta, duration) {
|
|
|
5278
5383
|
}
|
|
5279
5384
|
function coerceImageParam(value) {
|
|
5280
5385
|
if (typeof value === "string") return Promise.resolve(value);
|
|
5281
|
-
if (
|
|
5386
|
+
if (isAssetRefLike2(value)) return refToUrl(value);
|
|
5282
5387
|
throw new Error("hyperframe_render: image param must be a URL string or AssetRef");
|
|
5283
5388
|
}
|
|
5284
5389
|
async function substituteCompositionFiles(tmp, values) {
|
|
@@ -5508,7 +5613,7 @@ async function buildSubstitutionValues2(compositionParams, meta) {
|
|
|
5508
5613
|
}
|
|
5509
5614
|
function coerceImageParam2(value) {
|
|
5510
5615
|
if (typeof value === "string") return Promise.resolve(value);
|
|
5511
|
-
if (
|
|
5616
|
+
if (isAssetRefLike2(value)) return refToUrl(value);
|
|
5512
5617
|
throw new Error("hyperframe_snapshot: image param must be a URL string or AssetRef");
|
|
5513
5618
|
}
|
|
5514
5619
|
async function substituteCompositionFiles2(tmp, values) {
|
|
@@ -6534,17 +6639,29 @@ function createEngineFromEnv(opts = {}) {
|
|
|
6534
6639
|
const cacheDir = opts.cacheDir ?? path15.join(cwd, "canvas", ".cache");
|
|
6535
6640
|
const outputsDir = opts.outputsDir ?? path15.join(cwd, "canvas");
|
|
6536
6641
|
const creds = requireCredentialsFromEnv();
|
|
6642
|
+
const client = new BackendClient({ baseUrl: creds.url, apiKey: creds.apiKey });
|
|
6643
|
+
const assets = new LocalAssetStore(path15.join(cacheDir, "assets"));
|
|
6644
|
+
const localCache = new LocalCacheStore(path15.join(cacheDir, "index"));
|
|
6645
|
+
const remoteCacheEnabled = opts.remoteCache ?? remoteCacheEnabledFromEnv();
|
|
6646
|
+
const cache = remoteCacheEnabled ? new LayeredCacheStore({
|
|
6647
|
+
local: localCache,
|
|
6648
|
+
remote: new RemoteCacheStore(client, opts.log),
|
|
6649
|
+
assets,
|
|
6650
|
+
log: opts.log
|
|
6651
|
+
}) : localCache;
|
|
6537
6652
|
return new Engine({
|
|
6538
6653
|
registry: defaultRegistry(),
|
|
6539
|
-
client
|
|
6540
|
-
assets
|
|
6541
|
-
cache
|
|
6654
|
+
client,
|
|
6655
|
+
assets,
|
|
6656
|
+
cache,
|
|
6542
6657
|
outputsDir,
|
|
6543
|
-
log: opts.log
|
|
6658
|
+
log: opts.log,
|
|
6659
|
+
persistAssets: remoteCacheEnabled
|
|
6544
6660
|
});
|
|
6545
6661
|
}
|
|
6546
6662
|
|
|
6547
6663
|
export {
|
|
6664
|
+
requireCredentialsFromEnv,
|
|
6548
6665
|
LayerExecutionError,
|
|
6549
6666
|
describeFailureReason,
|
|
6550
6667
|
SEEDANCE_DURATIONS,
|
|
@@ -6552,7 +6669,10 @@ export {
|
|
|
6552
6669
|
IMAGE_GENERATE_MODELS,
|
|
6553
6670
|
MODEL_REGISTRY,
|
|
6554
6671
|
resolveConcurrency,
|
|
6555
|
-
|
|
6672
|
+
ulid,
|
|
6673
|
+
isPersistedAssetRef,
|
|
6674
|
+
collectAssetRefLikes,
|
|
6675
|
+
sha256Hex,
|
|
6556
6676
|
BackendClient2 as BackendClient,
|
|
6557
6677
|
Engine2 as Engine,
|
|
6558
6678
|
LocalAssetStore2 as LocalAssetStore,
|
|
@@ -6563,4 +6683,4 @@ export {
|
|
|
6563
6683
|
defaultRegistry,
|
|
6564
6684
|
createEngineFromEnv
|
|
6565
6685
|
};
|
|
6566
|
-
//# sourceMappingURL=chunk-
|
|
6686
|
+
//# sourceMappingURL=chunk-OCMOQOIJ.js.map
|