@koda-sl/baker-cli 0.120.0-dev.3bcc79f9c → 0.120.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.
@@ -1,32 +1,11 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
- // If the importer is in node compatibility mode or this is not an ESM
20
- // file that has been converted to a CommonJS file using a Babel-
21
- // compatible transform (i.e. "__esModule" has not been set), then set
22
- // "default" to the CommonJS "module.exports" for node compatibility.
23
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
- mod
25
- ));
1
+ import {
2
+ __commonJS,
3
+ __toESM
4
+ } from "./chunk-5WRI5ZAA.js";
26
5
 
27
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
6
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
28
7
  var require_safe_stable_stringify = __commonJS({
29
- "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
8
+ "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
30
9
  "use strict";
31
10
  var { hasOwnProperty } = Object.prototype;
32
11
  var stringify = configure2();
@@ -159,9 +138,9 @@ var require_safe_stable_stringify = __commonJS({
159
138
  }
160
139
  if (value) {
161
140
  return (value2) => {
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);
141
+ let message = `Object can not safely be stringified. Received type ${typeof value2}`;
142
+ if (typeof value2 !== "function") message += ` (${value2.toString()})`;
143
+ throw new Error(message);
165
144
  };
166
145
  }
167
146
  }
@@ -673,9 +652,6 @@ var HttpClient = class {
673
652
  async postJson(path16, body, signal) {
674
653
  return await this.requestJson("POST", path16, body, signal);
675
654
  }
676
- async putJson(path16, body, signal) {
677
- return await this.requestJson("PUT", path16, body, signal);
678
- }
679
655
  async getJson(path16, signal) {
680
656
  return await this.requestJson("GET", path16, void 0, signal);
681
657
  }
@@ -703,8 +679,8 @@ var HttpClient = class {
703
679
  try {
704
680
  const res = await this.fetchFn(url, {
705
681
  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),
682
+ headers: method === "POST" ? { "Content-Type": "application/json", Authorization: `Bearer ${this.apiKey}` } : { Authorization: `Bearer ${this.apiKey}` },
683
+ body: method === "POST" ? JSON.stringify(body) : void 0,
708
684
  signal: controller.signal
709
685
  });
710
686
  if (res.ok) return { kind: "value", value: await res.json() };
@@ -741,33 +717,33 @@ async function parseErrorBody(res) {
741
717
  const errObj = body.error ?? {};
742
718
  return classifyHttpError(res.status, errObj, errObj.message ?? `HTTP ${res.status}`);
743
719
  }
744
- function classifyHttpError(status, errObj, message2) {
720
+ function classifyHttpError(status, errObj, message) {
745
721
  if (errObj.code === CONTENT_POLICY_CODE) {
746
- return { kind: "content_policy", status, provider: errObj.provider, message: message2 };
722
+ return { kind: "content_policy", status, provider: errObj.provider, message };
747
723
  }
748
724
  if (status === 401 || status === 403) {
749
- return { kind: "unauthorized", status, message: message2 };
725
+ return { kind: "unauthorized", status, message };
750
726
  }
751
727
  if (status === 400 || status === 422) {
752
- return { kind: "validation", status, message: message2, details: errObj.details };
728
+ return { kind: "validation", status, message, details: errObj.details };
753
729
  }
754
730
  if (status === 502 || status === 504) {
755
731
  if (errObj.code === "provider_timeout" || status === 504) {
756
- return { kind: "timeout", provider: errObj.provider, message: message2 };
732
+ return { kind: "timeout", provider: errObj.provider, message };
757
733
  }
758
734
  return {
759
735
  kind: "provider",
760
736
  status,
761
737
  provider: errObj.provider,
762
738
  code: errObj.code ?? "provider_error",
763
- message: message2,
739
+ message,
764
740
  retryable: errObj.retryable ?? true
765
741
  };
766
742
  }
767
743
  if (status >= 500 || status === 429) {
768
- return { kind: "server", status, message: message2 };
744
+ return { kind: "server", status, message };
769
745
  }
770
- return { kind: "validation", status, message: message2, details: errObj.details };
746
+ return { kind: "validation", status, message, details: errObj.details };
771
747
  }
772
748
  function backoffMs(attempt) {
773
749
  return 1e3 * 2 ** attempt;
@@ -838,27 +814,6 @@ var BackendClient = class {
838
814
  signal
839
815
  );
840
816
  }
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
- }
862
817
  getArtifact(kind, name, version, signal) {
863
818
  const path16 = version ? `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}/${encodeURIComponent(version)}` : `/api/canvas/artifacts/${encodeURIComponent(kind)}/${encodeURIComponent(name)}`;
864
819
  return this.http.getJson(path16, signal);
@@ -882,17 +837,14 @@ function requireCredentialsFromEnv(env = process.env) {
882
837
  }
883
838
  return c;
884
839
  }
885
- function remoteCacheEnabledFromEnv(env = process.env) {
886
- return env.BAKER_CANVAS_REMOTE_CACHE !== "off";
887
- }
888
840
 
889
841
  // src/engine/engine/errors.ts
890
842
  function isBlocking(issue) {
891
843
  return issue.severity !== "warning";
892
844
  }
893
845
  var CanvasError = class extends Error {
894
- constructor(message2) {
895
- super(message2);
846
+ constructor(message) {
847
+ super(message);
896
848
  this.name = "CanvasError";
897
849
  }
898
850
  };
@@ -949,7 +901,7 @@ function describeCause(c) {
949
901
  }
950
902
  }
951
903
 
952
- // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
904
+ // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
953
905
  var import__ = __toESM(require_safe_stable_stringify(), 1);
954
906
  var configure = import__.default.configure;
955
907
  var wrapper_default = import__.default;
@@ -1610,158 +1562,6 @@ function encodeRandom() {
1610
1562
  return out;
1611
1563
  }
1612
1564
 
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
-
1765
1565
  // src/engine/schema/canvas.ts
1766
1566
  import { z } from "zod";
1767
1567
  var REF_PREFIX = "$ref:";
@@ -1823,7 +1623,11 @@ var VideoMeta = z.object({
1823
1623
  // Advisory: the scene's visual length vs the estimated spoken length, so
1824
1624
  // a reviewer can see a native line that may run past its cut. Not gated.
1825
1625
  scene_s: z.number().optional(),
1826
- est_speech_s: z.number().optional()
1626
+ est_speech_s: z.number().optional(),
1627
+ // Word count of the line est_speech_s was measured for. Together they carry
1628
+ // the speaker's OBSERVED pace (from the deconstruct's word timings), so the
1629
+ // overrun check budgets re-authored lines at the real rate, not a wps guess.
1630
+ speech_words: z.number().optional()
1827
1631
  }),
1828
1632
  z.object({ scene: z.number(), lipsync_node: z.string() })
1829
1633
  ])
@@ -2353,7 +2157,9 @@ var STAGE_CODES = {
2353
2157
  SPEECH_OVERRUN: "VIDEO_SPEECH_OVERRUN",
2354
2158
  ASPECT_MISMATCH: "VIDEO_ASPECT_MISMATCH",
2355
2159
  REFERENCE_MISSING: "VIDEO_REFERENCE_MISSING",
2356
- SPAN_EXCEEDS_MODEL: "VIDEO_SPAN_EXCEEDS_MODEL"
2160
+ SPAN_EXCEEDS_MODEL: "VIDEO_SPAN_EXCEEDS_MODEL",
2161
+ UI_IN_PROMPT: "VIDEO_UI_IN_PROMPT",
2162
+ BRANDMARK_IN_PROMPT: "VIDEO_BRANDMARK_IN_PROMPT"
2357
2163
  };
2358
2164
  var SPAN_MODEL_SLACK_S = 0.25;
2359
2165
  var VIDEO_TIME_SLACK_S = 0.75;
@@ -2732,6 +2538,8 @@ function checkVideoInvariants(ctx) {
2732
2538
  }
2733
2539
  checkSpeechOverrun(ctx, meta.talking_scenes);
2734
2540
  checkAspectConsistency(ctx);
2541
+ checkUiInPrompt(ctx);
2542
+ checkBrandmarkInPrompt(ctx);
2735
2543
  checkReferenceCompleteness(ctx, meta);
2736
2544
  checkClipSpanFitsModel(ctx, meta);
2737
2545
  }
@@ -2761,18 +2569,30 @@ function keywordTokens(text) {
2761
2569
  if (!text) return [];
2762
2570
  return text.toLowerCase().split(/[^a-z0-9]+/).filter((t) => t.length >= 3 && !KEYWORD_STOPWORDS.has(t));
2763
2571
  }
2764
- function keywordsForElement(el) {
2765
- const type = el.type.toLowerCase();
2766
- const typeWords = ELEMENT_TYPE_KEYWORDS[type] ?? [];
2572
+ function elementMentionKeywords(el) {
2573
+ const typeWords = ELEMENT_TYPE_KEYWORDS[el.type.toLowerCase()] ?? [];
2767
2574
  return [.../* @__PURE__ */ new Set([...typeWords, ...keywordTokens(el.label), ...keywordTokens(el.description)])];
2768
2575
  }
2576
+ function keywordsForElement(el) {
2577
+ return elementMentionKeywords(el);
2578
+ }
2769
2579
  function containsWord(text, word) {
2770
2580
  const esc = word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2771
2581
  return new RegExp(`\\b${esc}\\b`, "i").test(text);
2772
2582
  }
2583
+ var FRAME_DESCRIPTION_START = "FRAME DESCRIPTION (this frame's editable prompt):";
2584
+ var FRAME_DESCRIPTION_END = "Render exactly what the FRAME DESCRIPTION";
2585
+ function frameDescriptionOf(prompt) {
2586
+ const i = prompt.indexOf(FRAME_DESCRIPTION_START);
2587
+ if (i < 0) return prompt;
2588
+ const rest = prompt.slice(i + FRAME_DESCRIPTION_START.length);
2589
+ const j = rest.indexOf(FRAME_DESCRIPTION_END);
2590
+ return j < 0 ? rest : rest.slice(0, j);
2591
+ }
2773
2592
  function checkFrameReferences(ctx, node, index, keyworded) {
2774
- const prompt = node.params?.prompt;
2775
- if (typeof prompt !== "string" || prompt.length === 0) return;
2593
+ const rawPrompt = node.params?.prompt;
2594
+ if (typeof rawPrompt !== "string" || rawPrompt.length === 0) return;
2595
+ const prompt = frameDescriptionOf(rawPrompt);
2776
2596
  const inputsBlob = JSON.stringify(node.inputs ?? {});
2777
2597
  for (const { el, keywords } of keyworded) {
2778
2598
  if (inputsBlob.includes(el.ref)) continue;
@@ -2822,13 +2642,24 @@ function checkClipSpanFitsModel(ctx, meta) {
2822
2642
  });
2823
2643
  }
2824
2644
  }
2825
- function speechOverrunOf(node) {
2645
+ var OBSERVED_WPS_MIN = 1;
2646
+ var OBSERVED_WPS_MAX = 6;
2647
+ function secondsPerWord(stamped) {
2648
+ const est = stamped?.est_speech_s;
2649
+ const words = stamped?.speech_words;
2650
+ if (est && words && est > 0 && words > 0) {
2651
+ const wps = words / est;
2652
+ if (wps >= OBSERVED_WPS_MIN && wps <= OBSERVED_WPS_MAX) return est / words;
2653
+ }
2654
+ return 1 / SPEECH_WORDS_PER_SECOND;
2655
+ }
2656
+ function speechOverrunOf(node, secPerWord) {
2826
2657
  const params = node.params;
2827
2658
  if (params?.generate_audio !== true) return null;
2828
2659
  const line = nativeDialogueOf(params.prompt);
2829
2660
  const duration = typeof params.duration === "number" ? params.duration : void 0;
2830
2661
  if (!line || !duration) return null;
2831
- const estSpeechS = line.split(/\s+/).filter(Boolean).length / SPEECH_WORDS_PER_SECOND;
2662
+ const estSpeechS = line.split(/\s+/).filter(Boolean).length * secPerWord;
2832
2663
  return estSpeechS > duration * SPEECH_OVERRUN_RATIO ? { estSpeechS, duration } : null;
2833
2664
  }
2834
2665
  function checkSpeechOverrun(ctx, talkingScenes) {
@@ -2837,7 +2668,7 @@ function checkSpeechOverrun(ctx, talkingScenes) {
2837
2668
  const nativeClipRe = new RegExp(`^s${entry.scene}(_r\\d+)?_clip$`);
2838
2669
  for (const n of ctx.canvas.nodes) {
2839
2670
  if (!nativeClipRe.test(n.id) || n.type !== "video_generate") continue;
2840
- const overrun = speechOverrunOf(n);
2671
+ const overrun = speechOverrunOf(n, secondsPerWord(entry));
2841
2672
  if (!overrun) continue;
2842
2673
  ctx.issues.push({
2843
2674
  path: `nodes[${ctx.idToIndex.get(n.id) ?? -1}].params.prompt`,
@@ -2847,6 +2678,38 @@ function checkSpeechOverrun(ctx, talkingScenes) {
2847
2678
  }
2848
2679
  }
2849
2680
  }
2681
+ var UI_IN_PROMPT_RE = /\bscreen[- ]?(?:recording|capture|grab|share)\b|\bapp (?:interface|screen)\b|\bphone screen overlay\b/i;
2682
+ function checkUiInPrompt(ctx) {
2683
+ for (const n of ctx.canvas.nodes) {
2684
+ if (n.type !== "video_generate") continue;
2685
+ const prompt = n.params?.prompt;
2686
+ if (typeof prompt !== "string" || !UI_IN_PROMPT_RE.test(prompt)) continue;
2687
+ ctx.issues.push({
2688
+ path: `nodes[${ctx.idToIndex.get(n.id) ?? -1}].params.prompt`,
2689
+ code: STAGE_CODES.UI_IN_PROMPT,
2690
+ severity: "warning",
2691
+ 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`,
2692
+ node_id: n.id,
2693
+ node_type: "video_generate"
2694
+ });
2695
+ }
2696
+ }
2697
+ 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;
2698
+ function checkBrandmarkInPrompt(ctx) {
2699
+ for (const n of ctx.canvas.nodes) {
2700
+ if (n.type !== "video_generate" && n.type !== "image_generate") continue;
2701
+ const prompt = n.params?.prompt;
2702
+ if (typeof prompt !== "string" || !BRANDMARK_IN_PROMPT_RE.test(prompt)) continue;
2703
+ ctx.issues.push({
2704
+ path: `nodes[${ctx.idToIndex.get(n.id) ?? -1}].params.prompt`,
2705
+ code: STAGE_CODES.BRANDMARK_IN_PROMPT,
2706
+ severity: "warning",
2707
+ 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`,
2708
+ node_id: n.id,
2709
+ node_type: n.type
2710
+ });
2711
+ }
2712
+ }
2850
2713
  function checkAspectConsistency(ctx) {
2851
2714
  const clips = ctx.canvas.nodes.filter((n) => n.type === "video_generate");
2852
2715
  if (clips.length < 2) return;
@@ -2978,7 +2841,6 @@ var Engine = class {
2978
2841
  cache;
2979
2842
  outputsDir;
2980
2843
  log;
2981
- persistAssets;
2982
2844
  constructor(opts) {
2983
2845
  this.registry = opts.registry;
2984
2846
  this.client = opts.client;
@@ -2986,7 +2848,6 @@ var Engine = class {
2986
2848
  this.cache = opts.cache;
2987
2849
  this.outputsDir = opts.outputsDir;
2988
2850
  this.log = opts.log ?? (() => void 0);
2989
- this.persistAssets = opts.persistAssets ?? false;
2990
2851
  }
2991
2852
  validate(canvas) {
2992
2853
  return validateCanvas(canvas, this.registry);
@@ -3033,7 +2894,7 @@ var Engine = class {
3033
2894
  `[done ] ${stats.cached_nodes}/${stats.total_nodes} cached, ${stats.total_credits} credits, ${stats.duration_ms}ms`
3034
2895
  );
3035
2896
  this.log(`outputs in: ${writer.runDir}`);
3036
- return { run_id: runId, output, outputs_by_node: outputs, stats, outputs_dir: writer.runDir, node_runs: nodeRuns };
2897
+ return { run_id: runId, output, outputs_by_node: outputs, stats, outputs_dir: writer.runDir };
3037
2898
  }
3038
2899
  async runLayers(canvas, outputs, runId, writer, opts, counters, nodeRuns) {
3039
2900
  const layers = topologicalLayers(this.pruneToOutput(canvas, buildGraph(canvas)));
@@ -3130,14 +2991,6 @@ var Engine = class {
3130
2991
  const credits = def.cost ? def.cost({ params: parsedParams }).credits : 0;
3131
2992
  const outputsObj = result;
3132
2993
  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
- }
3141
2994
  if (policy === "read_write") {
3142
2995
  await this.cache.put({
3143
2996
  cacheKey: prepared.cacheKey,
@@ -3456,6 +3309,27 @@ var FontRef = BaseAssetRef.extend({
3456
3309
  });
3457
3310
  var AssetRef = z4.discriminatedUnion("kind", [ImageRef, VideoRef, AudioRef, JsonRef, TextRef, FontRef]);
3458
3311
 
3312
+ // src/engine/nodes/remote/upload.ts
3313
+ async function presignAndPut(args) {
3314
+ const { putUrl, publicUrl } = await args.ctx.client.presignAssetUpload(args.sha256, args.mime, args.ctx.signal);
3315
+ const putRes = await fetch(putUrl, {
3316
+ method: "PUT",
3317
+ body: new Uint8Array(args.bytes),
3318
+ headers: { "Content-Type": args.mime },
3319
+ signal: args.ctx.signal
3320
+ });
3321
+ if (!putRes.ok) {
3322
+ throw new Error(`upload: presigned PUT failed ${putRes.status} ${putRes.statusText}`);
3323
+ }
3324
+ return publicUrl;
3325
+ }
3326
+ async function ensureUploaded(ref, ctx) {
3327
+ if (ref.url) return ref;
3328
+ const bytes = await ctx.assets.readBytes(ref.sha256, ref.mime);
3329
+ const url = await presignAndPut({ bytes, sha256: ref.sha256, mime: ref.mime, ctx });
3330
+ return { ...ref, url };
3331
+ }
3332
+
3459
3333
  // src/engine/nodes/remote/delegate.ts
3460
3334
  function delegated(spec) {
3461
3335
  return {
@@ -3850,10 +3724,10 @@ function inferKindFromMime(mime) {
3850
3724
  if (mime.startsWith("font/")) return "font";
3851
3725
  return null;
3852
3726
  }
3853
- function localExecError(ctx, message2) {
3727
+ function localExecError(ctx, message) {
3854
3728
  return new NodeExecutionError(ctx.nodeId, ctx.nodeType, {
3855
3729
  kind: "local",
3856
- cause: new Error(`ingest: ${message2}`)
3730
+ cause: new Error(`ingest: ${message}`)
3857
3731
  });
3858
3732
  }
3859
3733
  async function execLocalFile(params, ctx) {
@@ -4520,7 +4394,7 @@ async function refToUrl(ref) {
4520
4394
  return `data:${ref.mime};base64,${bytes.toString("base64")}`;
4521
4395
  }
4522
4396
  var ASSET_KINDS = /* @__PURE__ */ new Set(["image", "video", "audio", "json", "text", "font"]);
4523
- function isAssetRefLike2(value) {
4397
+ function isAssetRefLike(value) {
4524
4398
  if (!value || typeof value !== "object") return false;
4525
4399
  const v = value;
4526
4400
  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");
@@ -4892,8 +4766,8 @@ var NEVER_BLOCK = [
4892
4766
  /text[_-]?occluded/i
4893
4767
  ];
4894
4768
  var UNAVAILABLE = /unknown command|command not found|not found|Did you mean|Unknown argument|ENOENT/i;
4895
- function isAdvisory(code, message2) {
4896
- const hay = `${code} ${message2}`;
4769
+ function isAdvisory(code, message) {
4770
+ const hay = `${code} ${message}`;
4897
4771
  return NEVER_BLOCK.some((re) => re.test(hay));
4898
4772
  }
4899
4773
  function parseCheckJson(raw) {
@@ -4921,10 +4795,10 @@ function classifyLint(json) {
4921
4795
  for (const f of findings) {
4922
4796
  const rec = f;
4923
4797
  const code = String(rec?.code ?? "");
4924
- const message2 = String(rec?.message ?? "");
4798
+ const message = String(rec?.message ?? "");
4925
4799
  const severity = String(rec?.severity ?? "info");
4926
- const blocking = severity === "error" && !isAdvisory(code, message2);
4927
- out.push({ source: "lint", code, message: message2, severity: blocking ? "blocking" : "warning" });
4800
+ const blocking = severity === "error" && !isAdvisory(code, message);
4801
+ out.push({ source: "lint", code, message, severity: blocking ? "blocking" : "warning" });
4928
4802
  }
4929
4803
  return out;
4930
4804
  }
@@ -4936,9 +4810,9 @@ function classifyInspect(json) {
4936
4810
  for (const iss of issues) {
4937
4811
  const rec = iss;
4938
4812
  const code = String(rec?.code ?? rec?.type ?? "overflow");
4939
- const message2 = String(rec?.message ?? rec?.detail ?? JSON.stringify(iss));
4813
+ const message = String(rec?.message ?? rec?.detail ?? JSON.stringify(iss));
4940
4814
  const severity = rec?.severity ? String(rec.severity) : obj?.ok === false ? "error" : "warning";
4941
- out.push({ source: "inspect", code, message: message2, severity: severity === "error" ? "blocking" : "warning" });
4815
+ out.push({ source: "inspect", code, message, severity: severity === "error" ? "blocking" : "warning" });
4942
4816
  }
4943
4817
  return out;
4944
4818
  }
@@ -5383,7 +5257,7 @@ async function buildSubstitutionValues(compositionParams, meta, duration) {
5383
5257
  }
5384
5258
  function coerceImageParam(value) {
5385
5259
  if (typeof value === "string") return Promise.resolve(value);
5386
- if (isAssetRefLike2(value)) return refToUrl(value);
5260
+ if (isAssetRefLike(value)) return refToUrl(value);
5387
5261
  throw new Error("hyperframe_render: image param must be a URL string or AssetRef");
5388
5262
  }
5389
5263
  async function substituteCompositionFiles(tmp, values) {
@@ -5613,7 +5487,7 @@ async function buildSubstitutionValues2(compositionParams, meta) {
5613
5487
  }
5614
5488
  function coerceImageParam2(value) {
5615
5489
  if (typeof value === "string") return Promise.resolve(value);
5616
- if (isAssetRefLike2(value)) return refToUrl(value);
5490
+ if (isAssetRefLike(value)) return refToUrl(value);
5617
5491
  throw new Error("hyperframe_snapshot: image param must be a URL string or AssetRef");
5618
5492
  }
5619
5493
  async function substituteCompositionFiles2(tmp, values) {
@@ -6639,29 +6513,17 @@ function createEngineFromEnv(opts = {}) {
6639
6513
  const cacheDir = opts.cacheDir ?? path15.join(cwd, "canvas", ".cache");
6640
6514
  const outputsDir = opts.outputsDir ?? path15.join(cwd, "canvas");
6641
6515
  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;
6652
6516
  return new Engine({
6653
6517
  registry: defaultRegistry(),
6654
- client,
6655
- assets,
6656
- cache,
6518
+ client: new BackendClient({ baseUrl: creds.url, apiKey: creds.apiKey }),
6519
+ assets: new LocalAssetStore(path15.join(cacheDir, "assets")),
6520
+ cache: new LocalCacheStore(path15.join(cacheDir, "index")),
6657
6521
  outputsDir,
6658
- log: opts.log,
6659
- persistAssets: remoteCacheEnabled
6522
+ log: opts.log
6660
6523
  });
6661
6524
  }
6662
6525
 
6663
6526
  export {
6664
- requireCredentialsFromEnv,
6665
6527
  LayerExecutionError,
6666
6528
  describeFailureReason,
6667
6529
  SEEDANCE_DURATIONS,
@@ -6669,10 +6531,7 @@ export {
6669
6531
  IMAGE_GENERATE_MODELS,
6670
6532
  MODEL_REGISTRY,
6671
6533
  resolveConcurrency,
6672
- ulid,
6673
- isPersistedAssetRef,
6674
- collectAssetRefLikes,
6675
- sha256Hex,
6534
+ elementMentionKeywords,
6676
6535
  BackendClient2 as BackendClient,
6677
6536
  Engine2 as Engine,
6678
6537
  LocalAssetStore2 as LocalAssetStore,
@@ -6683,4 +6542,4 @@ export {
6683
6542
  defaultRegistry,
6684
6543
  createEngineFromEnv
6685
6544
  };
6686
- //# sourceMappingURL=chunk-OCMOQOIJ.js.map
6545
+ //# sourceMappingURL=chunk-IWPAXJC3.js.map