@koda-sl/baker-cli 0.150.0 → 0.151.0-dev.4932063cd

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 CHANGED
@@ -3396,6 +3396,7 @@ Generate video. Async with polling. Two curated models.
3396
3396
  | `first_frame` | image | no | Starting keyframe (image-to-video) |
3397
3397
  | `last_frame` | image | no | Ending keyframe |
3398
3398
  | `reference` | image | no | Alternative to `first_frame` when only one image is given |
3399
+ | `references` | image[] | no | Reference-to-video: several images used as visual guidance (this person, this product) instead of an exact opening frame. **Mutually exclusive with `first_frame`** — when both are wired the frame wins and these are ignored, so pick one mode. |
3399
3400
 
3400
3401
  Accepted ref-image MIMEs vary by model — see per-model sections below.
3401
3402
 
@@ -4659,25 +4660,6 @@ baker landing critique spring-offer --full # also print advisory-tier findings
4659
4660
 
4660
4661
  Output is the standard envelope `{ ok, data, hints }` with `data = { advisory, slug, overall, counts, dimensions, findings }`. `dimensions` scores seven design families (typography, color, borders_depth, motion, spacing, copy, integrity) 0–1 (higher is better); `counts` is the block/warn/advisory tally.
4661
4662
 
4662
- ## Brand Fonts (`baker brand fonts`)
4663
-
4664
- Verifies that a brand's typefaces really load, and self-hosts them. A font that isn't actually available never announces itself — the browser substitutes its nearest fallback, so the page renders fine and is quietly off-brand. Reading a family name off a live site tells you what the CSS *asks for*, never what loads.
4665
-
4666
- ```bash
4667
- baker brand fonts check # are the brand's fonts real?
4668
- baker brand fonts fetch "DM Sans" # self-host, weights taken from global.css
4669
- baker brand fonts fetch "Manrope" --weights 500,700 # self-host specific weights
4670
- baker brand fonts fetch "Inter" --subsets latin,latin-ext # add accented-glyph coverage
4671
- ```
4672
-
4673
- - **`check`** asks Google Fonts what it *actually* serves for every family and weight `src/styles/global.css` requests, and reports `requested` / `served` / `missing` plus the available unicode subsets. It exits 2 with `FONT_NOT_SERVED` when the brand asks for something Google won't serve, and distinguishes an unknown family name from a family that exists at other weights — the fix differs.
4674
- - **Failures carry the numbers, so nothing needs a second call.** `check`'s error keeps the full per-family breakdown at `error.fix.families` (healthy families included, so a multi-family brand shows what not to touch), and both commands probe the standard weights to report the ones that *do* exist at `error.fix.served` — the remediation is "retry with one of these" rather than "run `check`", which would be the command that just failed.
4675
- - **`fetch`** downloads the family into `src/brand/fonts/` and prints the `@font-face` block to paste above `@theme`. Defaults to the `latin` subset; `--subsets latin,latin-ext` adds accented-glyph coverage for Spanish and Portuguese copy. One file per weight *and* subset, since Google ships them separately and `unicode-range` is carried through verbatim.
4676
- - **It does not edit `global.css` for you.** Paste the block, then drop that family from the Google `@import` — otherwise the page self-hosts *and* still calls Google. Record the weights in `src/brand/BRAND.md` in the same change.
4677
- - **Licensing:** Google Fonts are open-licensed and safe to self-host. A client's own commercial typeface is not — confirm before re-hosting one.
4678
-
4679
- Complements the offline `validate-brand-fonts` check that runs in the scaffold's `verify`: that one compares what `global.css` declares against what provides it, with no network. Only the network can answer whether Google really serves a given family and weight.
4680
-
4681
4663
  ## Help & Discovery
4682
4664
 
4683
4665
  Every command supports `--help` for usage info:
@@ -7,9 +7,9 @@ import {
7
7
  __toESM
8
8
  } from "./chunk-RK67WL4O.js";
9
9
 
10
- // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js
10
+ // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js
11
11
  var require_safe_stable_stringify = __commonJS({
12
- "../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/index.js"(exports, module) {
12
+ "../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/index.js"(exports, module) {
13
13
  "use strict";
14
14
  var { hasOwnProperty } = Object.prototype;
15
15
  var stringify = configure2();
@@ -1070,7 +1070,7 @@ function resolveAdaptFormats(params) {
1070
1070
  return params.formats ?? [];
1071
1071
  }
1072
1072
 
1073
- // ../../node_modules/.pnpm/safe-stable-stringify@2.5.0/node_modules/safe-stable-stringify/esm/wrapper.js
1073
+ // ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/810146e81bae4e3a061fe487864f2fde80c4b03b886877dc0f1fffbc6480b67e/node_modules/safe-stable-stringify/esm/wrapper.js
1074
1074
  var import__ = __toESM(require_safe_stable_stringify(), 1);
1075
1075
  var configure = import__.default.configure;
1076
1076
  var wrapper_default = import__.default;
@@ -1119,6 +1119,7 @@ var OPENROUTER_IMAGE_SIZE = ["1K", "2K", "4K"];
1119
1119
  var OPENROUTER_IMAGE_SIZE_EXTENDED = ["0.5K", ...OPENROUTER_IMAGE_SIZE];
1120
1120
  var OPENROUTER_IMAGE_QUALITY = ["auto", "low", "medium", "high"];
1121
1121
  var SEEDANCE_DURATIONS = [4, 5, 6, 8, 10, 12, 15];
1122
+ var KLING_DURATIONS = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
1122
1123
  var ELEVENLABS_OUTPUT_FORMATS = [
1123
1124
  "mp3_22050_32",
1124
1125
  "mp3_44100_32",
@@ -1412,7 +1413,7 @@ var MODEL_REGISTRY = {
1412
1413
  prompt: { kind: "string" },
1413
1414
  negative_prompt: { kind: "string" },
1414
1415
  aspect_ratio: { kind: "string", enum: ["16:9", "9:16"] },
1415
- resolution: { kind: "string", enum: ["720p", "1080p"] },
1416
+ resolution: { kind: "string", enum: ["720p", "1080p", "4K"] },
1416
1417
  duration: { kind: "number", enum: [4, 6, 8] },
1417
1418
  seed: { kind: "number" },
1418
1419
  generate_audio: { kind: "boolean" },
@@ -1424,9 +1425,14 @@ var MODEL_REGISTRY = {
1424
1425
  "kwaivgi/kling-v3.0-pro": {
1425
1426
  // Motion-transfer / dynamic multi-shot beats. Reachable through the default
1426
1427
  // OpenRouter gateway (generic video body — no google-vertex block), so it
1427
- // needs no direct-provider exception. Cost is usage-based (known from the
1428
- // provider response), so it has no pre-flight cost estimate. `cfg_scale`
1429
- // trades prompt adherence vs motion freedom; higher = closer to prompt.
1428
+ // needs no direct-provider exception. `cfg_scale` trades prompt adherence
1429
+ // vs motion freedom; higher = closer to prompt.
1430
+ //
1431
+ // Params below are the ones OpenRouter actually advertises for this model
1432
+ // (GET /api/v1/videos/models). Three were wrong before and each was a free
1433
+ // 400 or a silently unsupported knob: it renders 720p ONLY (1080p was
1434
+ // offered and rejected), it takes ANY duration from 3-15s (we allowed just
1435
+ // 5 and 10), and it does not support `seed` at all.
1430
1436
  label: "Kling 3.0",
1431
1437
  inputs: [],
1432
1438
  optional_inputs: [{ kind: "image", mimes: OPENROUTER_IMAGE_MIMES }],
@@ -1436,10 +1442,9 @@ var MODEL_REGISTRY = {
1436
1442
  // over-length prompt fails validate (free) not the billed call.
1437
1443
  prompt: { kind: "string", maxLength: 2500 },
1438
1444
  negative_prompt: { kind: "string" },
1439
- aspect_ratio: { kind: "string", enum: ["1:1", "16:9", "9:16"] },
1440
- resolution: { kind: "string", enum: ["720p", "1080p"] },
1441
- duration: { kind: "number", enum: [5, 10] },
1442
- seed: { kind: "number" },
1445
+ aspect_ratio: { kind: "string", enum: ["16:9", "9:16", "1:1"] },
1446
+ resolution: { kind: "string", enum: ["720p"] },
1447
+ duration: { kind: "number", enum: KLING_DURATIONS },
1443
1448
  generate_audio: { kind: "boolean" },
1444
1449
  cfg_scale: { kind: "number", min: 0, max: 1 }
1445
1450
  }
@@ -1455,7 +1460,7 @@ var MODEL_REGISTRY = {
1455
1460
  prompt: { kind: "string" },
1456
1461
  negative_prompt: { kind: "string" },
1457
1462
  aspect_ratio: { kind: "string", enum: ["16:9", "9:16"] },
1458
- resolution: { kind: "string", enum: ["720p", "1080p"] },
1463
+ resolution: { kind: "string", enum: ["720p", "1080p", "4K"] },
1459
1464
  duration: { kind: "number", enum: [4, 6, 8] },
1460
1465
  seed: { kind: "number" },
1461
1466
  generate_audio: { kind: "boolean" },
@@ -1777,6 +1782,58 @@ function validateValue(key, value, schema, model) {
1777
1782
  }
1778
1783
  }
1779
1784
 
1785
+ // ../canvas-contract/src/videoCost.ts
1786
+ var CREDITS_PER_USD = 100;
1787
+ var SEEDANCE_USD_PER_SECOND = {
1788
+ "480p": 0.18,
1789
+ "720p": 0.5,
1790
+ "1080p": 0.62,
1791
+ "4k": 0.62
1792
+ };
1793
+ var DEFAULT_VIDEO_RESOLUTION = "720p";
1794
+ var DEFAULT_VIDEO_DURATION_S = 5;
1795
+ function isSeedanceModel(model) {
1796
+ return model.startsWith("bytedance/seedance");
1797
+ }
1798
+ var FALLBACK_USD_PER_SECOND = 0.5;
1799
+ function seedanceUsdPerSecond(resolution) {
1800
+ return SEEDANCE_USD_PER_SECOND[resolution ?? DEFAULT_VIDEO_RESOLUTION] ?? FALLBACK_USD_PER_SECOND;
1801
+ }
1802
+ var USD_PER_SECOND = {
1803
+ // Kling publishes one flat rate across every resolution and mode.
1804
+ "kwaivgi/kling-v3.0-pro": { silent: 0.112, audio: 0.168 },
1805
+ // Veo prices 4K far above the base tier — and 4K is a selectable resolution,
1806
+ // so folding it into the base rate under-quotes the dearest clip we can make.
1807
+ "google/veo-3.1": {
1808
+ silent: 0.2,
1809
+ audio: 0.4,
1810
+ byResolution: { "4K": { silent: 0.4, audio: 0.6 } }
1811
+ },
1812
+ "google/veo-3.1-fast": {
1813
+ silent: 0.1,
1814
+ audio: 0.12,
1815
+ byResolution: {
1816
+ "720p": { silent: 0.08, audio: 0.1 },
1817
+ "4K": { silent: 0.25, audio: 0.3 }
1818
+ }
1819
+ }
1820
+ };
1821
+ function estimateVideoCostUsd({ model, duration, resolution, generateAudio }) {
1822
+ const seconds = duration ?? DEFAULT_VIDEO_DURATION_S;
1823
+ if (isSeedanceModel(model)) return seedanceUsdPerSecond(resolution) * seconds;
1824
+ const published = USD_PER_SECOND[model];
1825
+ if (published) {
1826
+ const rate = (resolution ? published.byResolution?.[resolution] : void 0) ?? published;
1827
+ return (generateAudio ? rate.audio : rate.silent) * seconds;
1828
+ }
1829
+ const dearestKnownRate = Math.max(...Object.values(SEEDANCE_USD_PER_SECOND));
1830
+ return dearestKnownRate * seconds;
1831
+ }
1832
+ function estimateVideoCredits(input) {
1833
+ const credits = estimateVideoCostUsd(input) * CREDITS_PER_USD;
1834
+ return Math.ceil(Number(credits.toFixed(6)));
1835
+ }
1836
+
1780
1837
  // src/engine/lib/concurrency.ts
1781
1838
  var DEFAULT_CONCURRENCY = 8;
1782
1839
  function resolveConcurrency(...candidates) {
@@ -2573,7 +2630,7 @@ function looksLikeHttpUrl(value) {
2573
2630
  var VEO_PERSON_GENERATION = "allow_adult";
2574
2631
  var VEO_NEGATIVE_PROMPT = "subtitles, captions, on-screen text, watermark, logo, warped face, distorted hands, extra fingers, low quality";
2575
2632
  var VEO_DURATIONS = [4, 6, 8];
2576
- var KLING_DURATIONS = [5, 10];
2633
+ var KLING_DURATIONS2 = [5, 10];
2577
2634
  var KLING_NEGATIVE_PROMPT = "warped face, distorted hands, extra fingers, morphing, flicker, on-screen text, watermark, low quality";
2578
2635
  var KLING_CFG_SCALE = 0.7;
2579
2636
  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}"`;
@@ -2619,7 +2676,7 @@ var KLING_PROFILE = {
2619
2676
  // Kling takes a negative_prompt PARAM instead (paramDefaults).
2620
2677
  keyframeInstruction: "Preserve the composition and colors of the first frame; animate the motion described.",
2621
2678
  wordBudget: 200,
2622
- durationSet: KLING_DURATIONS,
2679
+ durationSet: KLING_DURATIONS2,
2623
2680
  paramDefaults: { negative_prompt: KLING_NEGATIVE_PROMPT, cfg_scale: KLING_CFG_SCALE }
2624
2681
  };
2625
2682
  function clipProfileFor(modelId) {
@@ -7453,12 +7510,33 @@ var videoGenerateNode = delegated({
7453
7510
  inputs: z28.object({
7454
7511
  first_frame: ImageRef.optional(),
7455
7512
  last_frame: ImageRef.optional(),
7456
- reference: ImageRef.optional()
7513
+ reference: ImageRef.optional(),
7514
+ /**
7515
+ * Reference-to-video: several images the model uses as visual guidance
7516
+ * (this person, this product) instead of an exact opening frame. Mutually
7517
+ * exclusive with `first_frame` — OpenRouter treats a request carrying both
7518
+ * as image-to-video and ignores these, so wire one or the other.
7519
+ */
7520
+ references: z28.array(ImageRef).optional()
7457
7521
  }).loose(),
7458
7522
  params: VideoGenerateParams,
7459
7523
  outputs: z28.object({ video: VideoRef }).strict(),
7460
7524
  outputKinds: { video: "video" },
7461
- cost: () => ({ credits: 50, seconds_estimate: 120 })
7525
+ // Priced from the shared contract, so `validate`'s quote and the charge the
7526
+ // backend applies come from ONE table. A flat number here under-quoted a
7527
+ // 1080p 8s clip by ~10x, and the agent reads this out to the user as "this
7528
+ // will cost N" before spending it.
7529
+ cost: ({ params }) => ({
7530
+ credits: estimateVideoCredits({
7531
+ model: params.model,
7532
+ duration: params.duration,
7533
+ resolution: params.resolution,
7534
+ // Audio bills at a separate, higher rate on every model that offers it
7535
+ // (Veo 3.1 doubles), so omitting it quotes half the real cost.
7536
+ generateAudio: params.generate_audio
7537
+ }),
7538
+ seconds_estimate: 120
7539
+ })
7462
7540
  });
7463
7541
 
7464
7542
  // src/engine/nodes/remote/videoBackgroundRemove.ts
@@ -7941,4 +8019,4 @@ export {
7941
8019
  defaultRegistry,
7942
8020
  createEngineFromEnv
7943
8021
  };
7944
- //# sourceMappingURL=chunk-OO5BDH3J.js.map
8022
+ //# sourceMappingURL=chunk-S43JQWI2.js.map