@koda-sl/baker-cli 0.355.0-dev.c2de9a6fe → 0.356.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -28,6 +28,7 @@ import {
28
28
  clipDurationsFor,
29
29
  clipParamRecipe,
30
30
  clipProfileFor,
31
+ coercePathUrlToUrl,
31
32
  collectAssetRefLikes,
32
33
  createEngineFromEnv,
33
34
  defaultRegistry,
@@ -68,7 +69,7 @@ import {
68
69
  validateCanvasDeep,
69
70
  withoutCastName,
70
71
  ytDlpBlockSignal
71
- } from "./chunk-B7MLH3K6.js";
72
+ } from "./chunk-H3SAAHZA.js";
72
73
  import {
73
74
  csvOrJson,
74
75
  daysAgoIso,
@@ -33563,6 +33564,19 @@ function pageOf(args5) {
33563
33564
  ...size ? { pageSize: Number(size) } : {}
33564
33565
  };
33565
33566
  }
33567
+ function isWholePositive(raw) {
33568
+ return /^[1-9]\d*$/.test(String(raw));
33569
+ }
33570
+ function paginationError(args5) {
33571
+ if (args5.page !== void 0 && !isWholePositive(args5.page)) {
33572
+ return `--page takes a page number of a list report (1, 2, \u2026), not "${String(args5.page)}". To narrow a report to one page of the site, pass --landing <internalId> (from \`baker analytics landings\`), or read one path with \`baker analytics page --path /pricing\`.`;
33573
+ }
33574
+ const size = args5["page-size"];
33575
+ if (size !== void 0 && !isWholePositive(size)) {
33576
+ return `--page-size takes a number of rows (1 to 200), not "${String(size)}".`;
33577
+ }
33578
+ return null;
33579
+ }
33566
33580
  function requestBody(args5, options) {
33567
33581
  const candidates = {
33568
33582
  preset: options.preset,
@@ -33627,6 +33641,11 @@ async function runPreset(args5, options) {
33627
33641
  });
33628
33642
  process.exit(1);
33629
33643
  }
33644
+ const pagination = paginationError(args5);
33645
+ if (pagination) {
33646
+ writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message: pagination } });
33647
+ process.exit(1);
33648
+ }
33630
33649
  try {
33631
33650
  const response = await apiPost("/api/analytics/query", requestBody(args5, options));
33632
33651
  const requestedPlatform = args5.platform === void 0 ? "" : String(args5.platform);
@@ -36791,7 +36810,7 @@ function rewriteTarget(value, workspaceRoot) {
36791
36810
  }
36792
36811
  return null;
36793
36812
  }
36794
- function normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot) {
36813
+ function normalizeCanvasPaths(canvas, canvasDir, workspaceRoot) {
36795
36814
  if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
36796
36815
  const c = canvas;
36797
36816
  if (!Array.isArray(c.nodes)) return { canvas, rewrites: [] };
@@ -36804,6 +36823,10 @@ function normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot) {
36804
36823
  const params = n.params;
36805
36824
  if (!params || typeof params !== "object") return node;
36806
36825
  const nodeId = typeof n.id === "string" ? n.id : "?";
36826
+ if (n.type === "ingest" && params.source === "path" && looksLikeHttpUrl(params.path)) {
36827
+ rewrites.push({ nodeId, param: "source", from: "path", to: "url" });
36828
+ return { ...node, params: coercePathUrlToUrl(params) };
36829
+ }
36807
36830
  const key = n.type === "ingest" && params.source === "path" ? "path" : n.type === "hyperframe_render" ? "composition" : null;
36808
36831
  if (!key) return node;
36809
36832
  const target2 = rewriteTarget(params[key], root);
@@ -36814,11 +36837,11 @@ function normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot) {
36814
36837
  });
36815
36838
  return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes }, rewrites };
36816
36839
  }
36817
- async function healAbsoluteCanvasPaths(filePath, canvas) {
36840
+ async function healCanvasPaths(filePath, canvas) {
36818
36841
  const canvasDir = path5.dirname(filePath);
36819
36842
  const workspaceRoot = findWorkspaceRoot(canvasDir);
36820
36843
  if (!workspaceRoot) return { canvas, rewrites: [], text: null };
36821
- const normalized = normalizeAbsoluteCanvasPaths(canvas, canvasDir, workspaceRoot);
36844
+ const normalized = normalizeCanvasPaths(canvas, canvasDir, workspaceRoot);
36822
36845
  if (normalized.rewrites.length === 0) return { ...normalized, text: null };
36823
36846
  const text2 = `${JSON.stringify(normalized.canvas, null, 2)}
36824
36847
  `;
@@ -39896,18 +39919,10 @@ function dropUncastVoices(nodes) {
39896
39919
  if (node && node.type === "voice_select" && !referenced.has(node.id)) nodes.splice(i, 1);
39897
39920
  }
39898
39921
  }
39899
- function framesReuseRefusal(blueprint, elements, requested) {
39900
- if (requested !== "reuse") return void 0;
39901
- const showsPeople = (blueprint.global?.cast ?? []).length > 0 || elements.some((e) => e.type.toLowerCase() === "person");
39902
- if (!showsPeople) return void 0;
39903
- return "--frames reuse was not applied: this video shows people, and reusing its frames would put the source's actors into our ad. Every frame is generated instead, recast to the el_* references. Reuse applies only to a video with nobody in it.";
39904
- }
39905
- function scaffoldVideoCanvas(input, elementsInput, requested) {
39922
+ function scaffoldVideoCanvas(input, elementsInput, opts) {
39906
39923
  const blueprint = VideoBlueprint.parse(input);
39907
39924
  injectHookPhysicality(blueprint);
39908
39925
  const elements = RecurringElements.parse(elementsInput);
39909
- const reuseRefused = framesReuseRefusal(blueprint, elements, requested.frames);
39910
- const opts = reuseRefused ? { ...requested, frames: "generate" } : requested;
39911
39926
  const clock = spineClockFor(blueprint);
39912
39927
  const nodes = [];
39913
39928
  emitBlueprintIngests(opts, nodes);
@@ -40014,7 +40029,6 @@ function scaffoldVideoCanvas(input, elementsInput, requested) {
40014
40029
  }
40015
40030
  const todo = {
40016
40031
  ...buildVideoTodo(videoReport(input, elementsInput), overlays.length, floating.length, opts, blueprint),
40017
- ...reuseRefused ? { frames_reuse_refused: reuseRefused } : {},
40018
40032
  ...aspectRemapTodo(resolveAspect(blueprint.source?.aspect_ratio, opts.aspect, genAspectsFor(opts.videoModel))),
40019
40033
  model_constraints: buildModelConstraints()
40020
40034
  };
@@ -41769,12 +41783,12 @@ async function executeCanvasRun(opts) {
41769
41783
  }
41770
41784
  const attemptedSlug = creativeSlugFromCanvasPath(filePath);
41771
41785
  if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
41772
- const healed = await healAbsoluteCanvasPaths(filePath, parsed);
41786
+ const healed = await healCanvasPaths(filePath, parsed);
41773
41787
  parsed = healed.canvas;
41774
41788
  const canvasText = healed.text ?? raw;
41775
41789
  if (healed.rewrites.length > 0) {
41776
41790
  process.stderr.write(
41777
- `[canvas] rewrote ${healed.rewrites.length} absolute asset path(s) to canvas-relative \u2014 they resolve only in this workspace:
41791
+ `[canvas] rewrote ${healed.rewrites.length} asset reference(s) in the canvas file so it says what runs (absolute paths \u2192 canvas-relative, a URL in an ingest path \u2192 source "url"):
41778
41792
  ${describeRewrites(healed.rewrites)}
41779
41793
  `
41780
41794
  );
@@ -44822,12 +44836,6 @@ function videoDefinitionDescription(blueprint) {
44822
44836
  const product = g.branding?.product;
44823
44837
  return typeof product === "string" && product.trim() ? product.trim() : void 0;
44824
44838
  }
44825
- function framesModeReport(canvas, requested) {
44826
- const todo = canvas.metadata?.todo;
44827
- const mode = typeof todo?.frames_mode === "string" ? todo.frames_mode : requested;
44828
- const refused = typeof todo?.frames_reuse_refused === "string" ? todo.frames_reuse_refused : void 0;
44829
- return { frames_mode: mode, ...refused ? { frames_reuse_refused: refused } : {} };
44830
- }
44831
44839
  async function materializeReferenceVideo(fileArg2) {
44832
44840
  if (!/^https?:\/\//i.test(fileArg2)) return path26.resolve(fileArg2);
44833
44841
  let bytes;
@@ -44985,10 +44993,7 @@ var scaffoldVideoCommand = defineCommand116({
44985
44993
  type: "string",
44986
44994
  description: "Creative slug \u2014 writes the canvas to src/creatives/<slug>/<slug>.canvas.json (repo convention)"
44987
44995
  },
44988
- frames: {
44989
- type: "string",
44990
- description: `"generate" (default, every frame regenerated for our ad) or "reuse" (wire the source's real frames in). Reuse applies only to a video with nobody in it \u2014 on a video showing people it is refused and every frame is generated, so the source's actors never reach our ad.`
44991
- },
44996
+ frames: { type: "string", description: '"generate" (default, anchored regen) or "reuse" (wire real frames in)' },
44992
44997
  ambient: {
44993
44998
  type: "boolean",
44994
44999
  description: "Give silent b-roll scenes native diegetic ambient mixed deep under the music bed (off by default)"
@@ -45176,7 +45181,6 @@ var scaffoldVideoCommand = defineCommand116({
45176
45181
  error: { code: "validation", issues: validation.issues },
45177
45182
  canvas_path: outPath,
45178
45183
  prompt_path: blueprintPath,
45179
- ...framesModeReport(canvas, frames),
45180
45184
  note: "The canvas WAS written despite the blocking issue(s) \u2014 fix them in place, then `baker canvas validate` before running."
45181
45185
  },
45182
45186
  null,
@@ -45226,7 +45230,7 @@ var scaffoldVideoCommand = defineCommand116({
45226
45230
  source_reference: sourceRef.url,
45227
45231
  composition_dir: compositionDest,
45228
45232
  output: canvas.output,
45229
- ...framesModeReport(canvas, frames),
45233
+ frames_mode: frames,
45230
45234
  models: {
45231
45235
  deconstruct: deconstructModel,
45232
45236
  select: selectModel,
@@ -45377,7 +45381,7 @@ var validateCommand = defineCommand118({
45377
45381
  `);
45378
45382
  process.exit(2);
45379
45383
  }
45380
- const healed = await healAbsoluteCanvasPaths(filePath, parsed);
45384
+ const healed = await healCanvasPaths(filePath, parsed);
45381
45385
  parsed = healed.canvas;
45382
45386
  parsed = resolveRelativeCanvasPaths(parsed, path28.dirname(filePath));
45383
45387
  let styleProjection = "not_applicable";
@@ -68791,19 +68795,36 @@ function findUnknownFlags(root, argv) {
68791
68795
  }
68792
68796
  return unknown;
68793
68797
  }
68798
+ var SYNONYMS = {
68799
+ from: ["start-date", "start", "since"],
68800
+ since: ["start-date", "start"],
68801
+ start: ["start-date", "since"],
68802
+ to: ["end-date", "end", "until"],
68803
+ until: ["end-date", "end"],
68804
+ end: ["end-date", "until"],
68805
+ path: ["landing"],
68806
+ url: ["landing"]
68807
+ };
68794
68808
  function closestFlag(unknown, command) {
68795
68809
  const accepted = acceptedNames(command);
68796
68810
  if (!accepted) {
68797
68811
  return null;
68798
68812
  }
68799
68813
  const name = unknown.replace(/^--/, "").split("=")[0] ?? "";
68814
+ const synonym = SYNONYMS[name]?.find((candidate) => accepted.has(candidate));
68815
+ if (synonym) {
68816
+ return `--${synonym}`;
68817
+ }
68800
68818
  const scored = [...accepted].filter((candidate) => !ALWAYS_ACCEPTED.has(candidate)).map((candidate) => ({
68801
68819
  candidate,
68802
68820
  prefix: sharedPrefix(name, candidate),
68803
68821
  distance: editDistance(name, candidate)
68804
- })).filter(({ prefix, distance }) => prefix >= 4 || distance <= 3).sort((a, b) => b.prefix - a.prefix || a.distance - b.distance);
68822
+ })).filter(({ prefix, distance }) => prefix >= 4 || distance <= typoBudget(name)).sort((a, b) => b.prefix - a.prefix || a.distance - b.distance);
68805
68823
  return scored[0] ? `--${scored[0].candidate}` : null;
68806
68824
  }
68825
+ function typoBudget(name) {
68826
+ return Math.max(1, Math.floor(name.length / 3));
68827
+ }
68807
68828
  function sharedPrefix(a, b) {
68808
68829
  let i = 0;
68809
68830
  while (i < a.length && i < b.length && a[i] === b[i]) {
@@ -68827,6 +68848,24 @@ function commandFor(root, argv) {
68827
68848
  const { command, resolved } = resolveCommand2(root, argv);
68828
68849
  return resolved ? command : null;
68829
68850
  }
68851
+ function suggestFlag(unknown, command) {
68852
+ const flag = closestFlag(unknown, command);
68853
+ if (!flag) {
68854
+ return null;
68855
+ }
68856
+ const args5 = argsOf(command) ?? {};
68857
+ const name = flag.slice(2);
68858
+ const def = args5[name] ?? args5[camel(name)];
68859
+ const described = def && typeof def === "object" ? def.description : void 0;
68860
+ const description = typeof described === "string" ? described.split(/(?<!\b(?:e\.g|i\.e|vs))\.\s/)[0]?.trim().replace(/\.$/, "") : "";
68861
+ return description ? { flag, description } : { flag };
68862
+ }
68863
+ function suggestionText(suggestion) {
68864
+ if (!suggestion) {
68865
+ return "";
68866
+ }
68867
+ return suggestion.description ? `Did you mean ${suggestion.flag}? It is described as: ${suggestion.description}. ` : `Did you mean ${suggestion.flag}? `;
68868
+ }
68830
68869
  var OUTPUT_EXPLANATION = "This command has no --output option: `--output json` is accepted by every command that prints the JSON envelope, and md or files only where `baker schema` lists `output`. Drop the option and read the default output. ";
68831
68870
  function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
68832
68871
  const list = unknown.join(", ");
@@ -68837,7 +68876,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
68837
68876
  message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
68838
68877
  fix: {
68839
68878
  action: hasSchema ? "check_schema" : "check_help",
68840
- explanation: (unknown.some((flag) => flag === "--output" || flag.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + (suggestion ? `Did you mean ${suggestion}? ` : "") + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
68879
+ explanation: (unknown.some((flag) => flag === "--output" || flag.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + suggestionText(suggestion) + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
68841
68880
  },
68842
68881
  retryable: false
68843
68882
  }
@@ -68867,7 +68906,7 @@ function refuseUnknownFlags(root, argv) {
68867
68906
  }
68868
68907
  const command = commandFor(root, argv);
68869
68908
  const first = unknown[0];
68870
- const suggestion = command && first ? closestFlag(first, command) : null;
68909
+ const suggestion = command && first ? suggestFlag(first, command) : null;
68871
68910
  const path48 = commandPathOf(root, argv);
68872
68911
  process.stdout.write(
68873
68912
  `${JSON.stringify(unknownFlagEnvelope(unknown, path48, suggestion, findSchema(path48.split(" ")) !== void 0), null, 2)}