@koda-sl/baker-cli 0.449.0-dev.b6179c7f5 → 0.454.0-dev.c94fef7ea

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
@@ -1814,7 +1814,7 @@ baker creatives make <idea> [--slug <s>] [--adset <id>] [--reference <adId>] [--
1814
1814
  baker creatives learn [--days <n>] [--dry-run] # what each idea's ads did, written back onto the idea
1815
1815
  ```
1816
1816
 
1817
- - `brief` returns a verdict, not raw numbers: `account.bottleneck` is `hook`, `after_click`, `none` or `too_little_data`. A part that cannot be read says `unavailable`; the market search gets 10 seconds, so a slow ad library leaves it out rather than holding the brief. With no ideas on file, its hint lists the values `awareness`, `angle` and `format` take. `market` says what competitors' ads already say (the followed brands, else the library), how sophisticated the market is, and which awareness stages nobody speaks to.
1817
+ - `brief` returns a verdict, not raw numbers: `account.bottleneck` is `hook`, `after_click`, `none` or `too_little_data`. A part that cannot be read says `unavailable`; the market searches (the followed brands, and the library for what COMPANY.md's first line says the company sells, in a few words) run at once and get 12 seconds, so a slow ad library leaves them out rather than holding the brief. With no ideas on file, its hint lists the values `awareness`, `angle` and `format` take. `market` says what competitors' ads already say (the followed brands, else the library), how sophisticated the market is, and which awareness stages nobody speaks to.
1818
1818
  - `ideas` is free and local. An idea's `evidence` resolves to `src/content/insights/` entries, or it is an `explore` bet. Numbers must be in the Knowledge or our own customers' quotes (a Reddit, forum or web quote never sources a claim), no two ideas may share an angle and format, and a review or testimonial format needs a quote from our own customer.
1819
1819
  - `learn` pools each built idea's creatives, judges them against the rest of the account's cost per result and writes `status` (`winner`, `failed`, `inconclusive`, `testing`) and a frozen `result` onto the idea. `ideas` then warns when a new idea repeats a failed one.
1820
1820
  - `make` builds one idea. A static searches the idea's container for ads made for our viewer, checks the closest three with `winning-ads fit` and scaffolds from the first that fits. For a new creative it starts scaffolding the best-ranked one while the fits are asked (kept when it fits, stopped and removed whole when another or none is kept), so the reference's describe pass no longer waits for them. A creative whose ad is already written is never built over (`ALREADY_MADE`): edit its `prompt.json`, or pass `--slug` for another ad of the same idea. A video idea takes its beats spec. Either way it records the idea on `_definition.md`, sets `prompt.json`'s `message` and syncs the definition. Drafted copy lines claiming a figure the company never wrote come back first in `hints`. When no proven ad fits (or with `--from-idea`), a static starts from the idea itself: `prompt.json` holds the message and placeholders, and `canvas run` refuses to render until the scene and copy are written.
@@ -6600,7 +6600,7 @@ With `--slug`, `data.variantChoice` (`runId`, `option`, `sha256`) says which var
6600
6600
  Record what the person said about one version in a chat: an approval, or a rejection with reasons and their own words. It is stored like the Approve / Not this one buttons, as the verdict of the person who wrote the chat's latest message (`recordedFor: "sender"`), or of the chat itself when nobody has written in it (`"chat"`). One verdict per person per version or option: a later one replaces theirs. Must run from a chat.
6601
6601
 
6602
6602
  ```bash
6603
- baker creatives feedback record --slug spring-offer --run r_01K… --verdict rejected \
6603
+ baker creatives feedback record --slug spring-offer --verdict rejected \
6604
6604
  --reasons text_mistakes,weak_hook --note "the price is 49 not 59"
6605
6605
  baker creatives feedback record --slug spring-offer --run r_01K… --option 2 --verdict approved
6606
6606
  ```
@@ -6608,7 +6608,7 @@ baker creatives feedback record --slug spring-offer --run r_01K… --option 2 --
6608
6608
  | Flag | Effect |
6609
6609
  |---|---|
6610
6610
  | `--slug <slug>` | Required. The creative (`src/creatives/<slug>/`). |
6611
- | `--run <r_…>` | Required. The version. |
6611
+ | `--run <r_…>` | The version. Left out, the one the creative shows now (its last render in this workspace). |
6612
6612
  | `--verdict approved\|rejected` | Required. |
6613
6613
  | `--option <o>` | One option of a version that made several: its label, its number (`2`) or its slot. |
6614
6614
  | `--reasons <a,b>` | Comma-separated: `text_mistakes`, `logo_or_brand_wrong`, `weak_hook`, `wrong_message`, `looks_fake`, `not_our_style`, `voice_or_sound`, `pacing`, `other`. The two video reasons: `voice_or_sound` (the voiceover, music or mix) and `pacing` (too slow, too fast, the hook lands late). A rejection needs reasons or a note. |
@@ -6621,7 +6621,7 @@ After a rejection, `hints[]` restates what to change, starting from that version
6621
6621
  Choose the version of a creative to keep, or only some of its options, the way choosing it in Baker does: the creative shows that version as the chosen one, and the choice records the chat sender's approval (`source: "selection"`). Naming options replaces the earlier pick. It does not add the image to the library; that is `baker creatives publish`, which, given `--run-id`, also counts as choosing that version.
6622
6622
 
6623
6623
  ```bash
6624
- baker creatives select --slug spring-offer --run r_01K…
6624
+ baker creatives select --slug spring-offer # the version it shows now
6625
6625
  baker creatives select --slug spring-offer --run r_01K… --options "beach,2"
6626
6626
  ```
6627
6627
 
@@ -6754,13 +6754,19 @@ var Viewer = z7.object({
6754
6754
  /** Who will see the ad, in the words a marketer would use. */
6755
6755
  who: z7.string().trim().min(1),
6756
6756
  market: Market.optional(),
6757
- /** What they already know about the brand and the offer. */
6758
- knows: z7.string().optional(),
6757
+ /** What they already know about the brand and the offer; a list (as _definition.md keeps it) reads as one line. */
6758
+ knows: z7.preprocess((v) => Array.isArray(v) ? v.map(String).join("; ") || void 0 : v, z7.string().optional()),
6759
6759
  temperature: z7.enum(["cold", "warm", "hot"]).optional(),
6760
6760
  /** Where they meet it (feed, Stories, Reels). */
6761
6761
  placement: z7.string().optional()
6762
6762
  }).strict();
6763
- var Scene = z7.object({
6763
+ var withoutFormatName = (v) => {
6764
+ if (!v || typeof v !== "object" || Array.isArray(v) || typeof v.concept !== "string")
6765
+ return v;
6766
+ const { concept: _format, ...scene } = v;
6767
+ return scene;
6768
+ };
6769
+ var SceneFields = z7.object({
6764
6770
  description: z7.string().trim().min(1),
6765
6771
  /** A photograph, a designed graphic, or an illustration. */
6766
6772
  look: z7.enum(["photo", "designed", "illustration"]),
@@ -6770,6 +6776,7 @@ var Scene = z7.object({
6770
6776
  /** How the frame is arranged, by what fills each part of it. */
6771
6777
  layout: z7.string().optional()
6772
6778
  }).strict();
6779
+ var Scene = z7.preprocess(withoutFormatName, SceneFields);
6773
6780
  var Brand = z7.object({
6774
6781
  name: z7.string().optional(),
6775
6782
  /** The words the brand's logo prints (its wordmark), so a check reads them as the logo, never as copy. */
@@ -6847,7 +6854,10 @@ var AdSpecSchema = z7.object({
6847
6854
  /** An optional note on direction for this concept. */
6848
6855
  direction: z7.string().optional(),
6849
6856
  /** The device the ad is built on, and why it works on a stranger. Judged, never drawn. */
6850
- mechanism: z7.array(Mechanism).default([]),
6857
+ mechanism: z7.preprocess(
6858
+ (v) => v && typeof v === "object" && !Array.isArray(v) ? [v] : v,
6859
+ z7.array(Mechanism).default([])
6860
+ ),
6851
6861
  /** Why the reference won and what this ad keeps of it (schema /3). */
6852
6862
  concept: Concept.optional(),
6853
6863
  /**
@@ -16042,6 +16052,22 @@ function everySizeChecks(opts) {
16042
16052
  onSpend: opts.onSpend
16043
16053
  };
16044
16054
  }
16055
+ async function confirmBlocking(findings, stills, formats, ask2) {
16056
+ const claims = findings.filter((f) => f.severity === "blocking");
16057
+ if (claims.length === 0 || stills.length === 0) return [...findings];
16058
+ const prompt = [
16059
+ `These are the finished sizes of one ad, in order: ${formats.map((f, i) => `Image ${i + 1} is the ${f}`).join("; ")}.`,
16060
+ "A reviewer reported each claim below. Look again at the size each one names (and, for a claim comparing sizes, at the others) and answer true only when the defect is plainly there for someone looking at it on a phone.",
16061
+ "Answer false when the thing is not there, when it is an ordinary part of the scene (a second house, a neighbour's roof, a reflection), or when the sizes it compares show the same thing.",
16062
+ ...claims.map((c, i) => `${i + 1}. ${c.what}`),
16063
+ `Reply with only this JSON: {"answers":[true|false, ...]}, one answer per claim, in order.`
16064
+ ].join("\n");
16065
+ const answer = await ask2([...stills], prompt).catch(() => null);
16066
+ const answers = answer?.answers;
16067
+ if (!Array.isArray(answers) || answers.length !== claims.length) return [...findings];
16068
+ const unconfirmed = new Set(claims.filter((_, i) => answers[i] === false));
16069
+ return findings.map((f) => unconfirmed.has(f) ? { ...f, severity: "warning" } : f);
16070
+ }
16045
16071
  async function reviewRenderedStatic(opts) {
16046
16072
  const { measured, originals, stills, thumbs } = await loadDelivered(opts.images);
16047
16073
  if (measured.length === 0) return null;
@@ -16072,7 +16098,14 @@ async function reviewRenderedStatic(opts) {
16072
16098
  if (answer === null) return unreviewed(shape, measuredText);
16073
16099
  const text2 = read ? measuredText : copyFindings(answer, opts.copy, formats, opts.scrolled);
16074
16100
  const boxesByFormat = read ? Object.fromEntries(checks.flatMap((c, i) => c.status === "checked" ? [[formats[i] ?? "", c.boxes]] : [])) : {};
16075
- return [...shape, ...text2, ...corroborateEdgeClaims(classifyStaticFindings(answer), boxesByFormat, lines)];
16101
+ const judged = corroborateEdgeClaims(classifyStaticFindings(answer), boxesByFormat, lines);
16102
+ const confirmed = await confirmBlocking(
16103
+ judged,
16104
+ stills,
16105
+ formats,
16106
+ (images, prompt) => askAboutStills(images, prompt, opts.onSpend)
16107
+ );
16108
+ return [...shape, ...text2, ...confirmed];
16076
16109
  }
16077
16110
 
16078
16111
  // src/engine/nodes/local/staticNative.ts
@@ -18698,4 +18731,4 @@ export {
18698
18731
  defaultRegistry,
18699
18732
  createEngineFromEnv
18700
18733
  };
18701
- //# sourceMappingURL=chunk-Y33XAZ5M.js.map
18734
+ //# sourceMappingURL=chunk-MYOTW5GV.js.map