@koda-sl/baker-cli 0.445.0-dev.71ff4e44a → 0.449.0-dev.b6179c7f5
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 +5 -5
- package/dist/{chunk-CYZ7H4F5.js → chunk-Y33XAZ5M.js} +189 -110
- package/dist/chunk-Y33XAZ5M.js.map +1 -0
- package/dist/cli.js +176 -81
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.d.ts +3 -6
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-CYZ7H4F5.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
SEEDANCE_DURATIONS,
|
|
46
46
|
SEEDANCE_PROFILE,
|
|
47
47
|
SOUND_EFFECT_MODEL,
|
|
48
|
+
SPEC_SHAPES_HINT,
|
|
48
49
|
SPOKEN_CLIP_DURATION_S,
|
|
49
50
|
SPOKEN_WORDS_PER_SECOND,
|
|
50
51
|
STATIC_ADAPT_FORMAT_ROLE,
|
|
@@ -200,7 +201,7 @@ import {
|
|
|
200
201
|
withoutCastName,
|
|
201
202
|
wordCount,
|
|
202
203
|
ytDlpBlockSignal
|
|
203
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-Y33XAZ5M.js";
|
|
204
205
|
import {
|
|
205
206
|
NAME_CONTAINS_ARG,
|
|
206
207
|
csvOrJson,
|
|
@@ -71147,7 +71148,10 @@ function fieldProblems(f) {
|
|
|
71147
71148
|
"message is missing: the one promise a stranger should get, what is offered and what changes for them"
|
|
71148
71149
|
);
|
|
71149
71150
|
if (!f.why) problems.push("why is missing: the brief finding it answers");
|
|
71150
|
-
if (!f.awareness)
|
|
71151
|
+
if (!f.awareness) {
|
|
71152
|
+
const written = f.awarenessWritten ? `"${f.awarenessWritten}" ` : "";
|
|
71153
|
+
problems.push(`awareness ${written}must be one of ${AWARENESS_STAGES.join(", ")}`);
|
|
71154
|
+
}
|
|
71151
71155
|
if (!(f.angle && IDEA_ANGLES.includes(f.angle)))
|
|
71152
71156
|
problems.push(`angle ${f.angle ? `"${f.angle}" ` : ""}must be one of ${IDEA_ANGLES.join(", ")}`);
|
|
71153
71157
|
if (!(f.format && IDEA_FORMATS.includes(f.format)))
|
|
@@ -71164,7 +71168,8 @@ function parseIdea(id, markdown) {
|
|
|
71164
71168
|
why: text2(fm.why),
|
|
71165
71169
|
angle: text2(fm.angle),
|
|
71166
71170
|
format: text2(fm.format),
|
|
71167
|
-
awareness: oneOf(AWARENESS_STAGES, fm.awareness)
|
|
71171
|
+
awareness: oneOf(AWARENESS_STAGES, fm.awareness),
|
|
71172
|
+
awarenessWritten: text2(fm.awareness)
|
|
71168
71173
|
};
|
|
71169
71174
|
const problems = fieldProblems(f);
|
|
71170
71175
|
const { who, message, why, angle, format, awareness } = f;
|
|
@@ -71730,33 +71735,45 @@ async function staticSpecGate(canvas, canvasDir) {
|
|
|
71730
71735
|
fix: "Write the ad in prompt.json: the scene the viewer sees and each line of copy as it prints. Then re-run."
|
|
71731
71736
|
};
|
|
71732
71737
|
}
|
|
71733
|
-
const
|
|
71734
|
-
|
|
71735
|
-
|
|
71736
|
-
|
|
71737
|
-
|
|
71738
|
-
fix: "Edit prompt.json: every word or figure the picture shows is a `copy` line (`in_scene`, with `on`); describe any other surface without words. Then re-run."
|
|
71739
|
-
};
|
|
71740
|
-
}
|
|
71741
|
-
const concept = conceptProblems(spec);
|
|
71742
|
-
if (concept.length > 0) {
|
|
71743
|
-
return {
|
|
71744
|
-
code: "concept_does_not_fit",
|
|
71745
|
-
problems: concept,
|
|
71746
|
-
fix: "Edit prompt.json's `concept`: name what of ours carries each missing element (`ours`), or pick another reference with `baker winning-ads fit`. Never render a copy that has lost what the reference wins on."
|
|
71747
|
-
};
|
|
71748
|
-
}
|
|
71738
|
+
const concept = {
|
|
71739
|
+
code: "concept_does_not_fit",
|
|
71740
|
+
problems: conceptProblems(spec),
|
|
71741
|
+
fix: "Edit prompt.json's `concept`: name what of ours carries each missing element (`ours`), or pick another reference with `baker winning-ads fit`. Never render a copy that has lost what the reference wins on."
|
|
71742
|
+
};
|
|
71749
71743
|
const root = await findBrandRoot(canvasDir) ?? findWorkspaceRoot(canvasDir) ?? canvasDir;
|
|
71750
71744
|
const records = await readRecords(root);
|
|
71751
|
-
|
|
71752
|
-
|
|
71753
|
-
|
|
71754
|
-
|
|
71755
|
-
|
|
71756
|
-
|
|
71757
|
-
|
|
71758
|
-
|
|
71759
|
-
|
|
71745
|
+
const gates = spec.native ? [
|
|
71746
|
+
concept,
|
|
71747
|
+
{
|
|
71748
|
+
// A native screen's people are photos it describes, briefed as ordinary people of the market.
|
|
71749
|
+
code: "native_screen_invalid",
|
|
71750
|
+
problems: nativeGateProblems(spec.native, records, spec.brand?.name),
|
|
71751
|
+
fix: "Fix prompt.json's `native` block."
|
|
71752
|
+
}
|
|
71753
|
+
] : [
|
|
71754
|
+
{
|
|
71755
|
+
// Words the scene asks for that the copy does not hold: refused here, free, rather than erased by a paid round.
|
|
71756
|
+
code: "scene_words_not_in_copy",
|
|
71757
|
+
problems: sceneWordProblems(spec),
|
|
71758
|
+
fix: "Edit prompt.json: every word or figure the picture shows is a `copy` line (`in_scene`, with `on`); describe any other surface without words."
|
|
71759
|
+
},
|
|
71760
|
+
concept,
|
|
71761
|
+
{
|
|
71762
|
+
code: "proof_without_source",
|
|
71763
|
+
problems: proofProblems(spec, records),
|
|
71764
|
+
fix: "Wire the badge or drop the claim in prompt.json, everywhere it appears (copy and scene)."
|
|
71765
|
+
}
|
|
71766
|
+
];
|
|
71767
|
+
return oneRefusal(gates.filter((g) => g.problems.length > 0));
|
|
71768
|
+
}
|
|
71769
|
+
function oneRefusal(gates) {
|
|
71770
|
+
const first = gates[0];
|
|
71771
|
+
if (!first) return null;
|
|
71772
|
+
return {
|
|
71773
|
+
code: first.code,
|
|
71774
|
+
problems: [...new Set(gates.flatMap((g) => g.problems))],
|
|
71775
|
+
fix: `${gates.map((g) => g.fix).join(" ")} Then re-run.`
|
|
71776
|
+
};
|
|
71760
71777
|
}
|
|
71761
71778
|
async function readRecords(root) {
|
|
71762
71779
|
const parts = [await readFile12(path14.join(root, "COMPANY.md"), "utf8").catch(() => "")];
|
|
@@ -73565,6 +73582,7 @@ var PAST_BAND = /^(.+?) sits? (?:close to )?where (.+?) covers? (?:it|them) \((.
|
|
|
73565
73582
|
var OFF_EDGE = /^(.+?) runs? off the edge of the picture \((.+)\)\.?$/;
|
|
73566
73583
|
var OUTSIDE_SPACE = /^(.+?) sits? outside the space every size keeps clear \((.+)\)\.?$/;
|
|
73567
73584
|
var EXTRA_WORDS = /^the picture adds words that aren't in the copy: (.+?)\. Remove them, or add them to the copy\.?$/;
|
|
73585
|
+
var SCENE_PRICES = /^the picture shows prices the copy does not hold: (.+?)\. Make them unreadable\.?$/;
|
|
73568
73586
|
var PLACED = [PAST_BAND, OFF_EDGE, OUTSIDE_SPACE];
|
|
73569
73587
|
var MISREAD = /^Text: (".+") reads (".*")\.?$/;
|
|
73570
73588
|
var MISSING = /^Text: (".+") is missing\.?$/;
|
|
@@ -73600,19 +73618,25 @@ function correctionOf(finding, band) {
|
|
|
73600
73618
|
if (extra) {
|
|
73601
73619
|
return `Erase these words wherever they appear, leaving the surface they are on blank or with plain lines: ${extra[1]}.`;
|
|
73602
73620
|
}
|
|
73621
|
+
const prices = what.match(SCENE_PRICES);
|
|
73622
|
+
if (prices) {
|
|
73623
|
+
return `Blur these figures until no digit can be read, keeping the document or screen they are on as it is: ${prices[1]}.`;
|
|
73624
|
+
}
|
|
73603
73625
|
const misread2 = what.match(MISREAD);
|
|
73604
73626
|
if (misread2) return `Re-letter ${misread2[1]} exactly as written, letter for letter (it now reads ${misread2[2]}).`;
|
|
73605
73627
|
const missing = what.match(MISSING);
|
|
73606
73628
|
if (missing) return `Add the line ${missing[1]}, spelled exactly, where it belongs in the layout.`;
|
|
73629
|
+
if (SIZES_FINDING.test(what)) return FOLLOW_PICTURE;
|
|
73607
73630
|
const described2 = what.replace(CATEGORY, "").replace(/\.$/, "");
|
|
73608
73631
|
return `Fix this: ${described2.charAt(0).toLowerCase()}${described2.slice(1)}.`;
|
|
73609
73632
|
}
|
|
73610
73633
|
function autoFixStep(canvas, review, opts = {}) {
|
|
73611
73634
|
if ((opts.round ?? 0) >= AUTO_FIX_ROUNDS) return null;
|
|
73612
|
-
const
|
|
73613
|
-
if (
|
|
73614
|
-
if (isNativeCanvas(canvas)) return { kind: "respec", findings: unique(
|
|
73635
|
+
const flagged = (review ?? []).filter((f) => f.severity === "blocking");
|
|
73636
|
+
if (flagged.length === 0) return null;
|
|
73637
|
+
if (isNativeCanvas(canvas)) return { kind: "respec", findings: unique(flagged.map((f) => f.what)) };
|
|
73615
73638
|
const relaid = relaidSizes(canvas);
|
|
73639
|
+
const blocking = onDerivedSizes(flagged, relaid);
|
|
73616
73640
|
const unplaceable = new Set((opts.tooFar ?? []).filter((format) => relaid.some((r) => r.format === format)));
|
|
73617
73641
|
const misplaced = (f) => {
|
|
73618
73642
|
const what = withoutSize(f.what);
|
|
@@ -73656,8 +73680,8 @@ function autoFixStep(canvas, review, opts = {}) {
|
|
|
73656
73680
|
pictureFindings.filter((f) => !BRIEF.test(withoutSize(f.what))).flatMap((f) => correctionOf(f.what) ?? [])
|
|
73657
73681
|
);
|
|
73658
73682
|
if (changes.length === 0) return sizesOnly();
|
|
73659
|
-
const
|
|
73660
|
-
const keep = relaid.map((r) => r.format).filter((format) => !
|
|
73683
|
+
const named = new Set(blocking.flatMap((f) => sizesOf(f.what)));
|
|
73684
|
+
const keep = relaid.map((r) => r.format).filter((format) => !named.has(format));
|
|
73661
73685
|
const remade = every.filter((size) => !keep.includes(size));
|
|
73662
73686
|
const kept = {
|
|
73663
73687
|
...keep.length > 0 ? { keep } : {},
|
|
@@ -73670,6 +73694,17 @@ function autoFixStep(canvas, review, opts = {}) {
|
|
|
73670
73694
|
return { kind: "fix", instruction, ...Object.keys(edits).length > 0 ? { relay: edits } : {}, ...kept };
|
|
73671
73695
|
}
|
|
73672
73696
|
var unique = (lines) => [...new Set(lines)];
|
|
73697
|
+
var SIZES_FINDING = /^SIZES:/i;
|
|
73698
|
+
var FOLLOW_PICTURE = "Show exactly what the finished ad (Image 2) shows: its people, products, panels and their order, and nothing it does not show.";
|
|
73699
|
+
function onDerivedSizes(findings, relaid) {
|
|
73700
|
+
if (relaid.length === 0) return [...findings];
|
|
73701
|
+
return findings.flatMap((f) => {
|
|
73702
|
+
const sizes = sizesOf(f.what);
|
|
73703
|
+
const onPicture = sizes.length > 0 && sizes.every((size) => !relaid.some((r) => r.format === size));
|
|
73704
|
+
if (!onPicture || !SIZES_FINDING.test(withoutSize(f.what))) return [f];
|
|
73705
|
+
return relaid.map((r) => ({ ...f, what: `${r.format}: ${withoutSize(f.what)}` }));
|
|
73706
|
+
});
|
|
73707
|
+
}
|
|
73673
73708
|
function deliveredSizes(canvas) {
|
|
73674
73709
|
const nodes = canvas?.nodes;
|
|
73675
73710
|
const labels = Array.isArray(nodes) ? nodes.find((n) => n.id === "final" && n.type === "collect")?.params?.labels : void 0;
|
|
@@ -73897,7 +73932,7 @@ var CHOSEN = [
|
|
|
73897
73932
|
(id, out) => id === "ad" && out.role === void 0
|
|
73898
73933
|
];
|
|
73899
73934
|
function urlOf(out) {
|
|
73900
|
-
const url = out.images?.find((o) => typeof o?.url === "string")?.url ?? out.image?.url;
|
|
73935
|
+
const url = out.images?.find((o) => typeof o?.url === "string")?.url ?? out.image?.url ?? out.asset?.url;
|
|
73901
73936
|
return typeof url === "string" ? url : null;
|
|
73902
73937
|
}
|
|
73903
73938
|
function chosenUrl(byNode) {
|
|
@@ -74141,7 +74176,7 @@ function turnRenderRefusal(ledger, turnId, slug) {
|
|
|
74141
74176
|
return {
|
|
74142
74177
|
code: "CONFLICT",
|
|
74143
74178
|
message: `This ad was rendered twice in this turn, its automatic corrections included, and is still not ready.`,
|
|
74144
|
-
fix:
|
|
74179
|
+
fix: `Show the best version as a version ("Version 3"), never a file path or a run id, and say in one plain sentence what is left, in the person's words. End there: no question and no options; their next message says what changes.`
|
|
74145
74180
|
};
|
|
74146
74181
|
}
|
|
74147
74182
|
return null;
|
|
@@ -75278,7 +75313,7 @@ var runCommand = defineCommand139({
|
|
|
75278
75313
|
},
|
|
75279
75314
|
concurrency: {
|
|
75280
75315
|
type: "string",
|
|
75281
|
-
description: "Max nodes
|
|
75316
|
+
description: "Max nodes running at once (default 8; env BAKER_CANVAS_CONCURRENCY)"
|
|
75282
75317
|
},
|
|
75283
75318
|
parallel: {
|
|
75284
75319
|
type: "string",
|
|
@@ -75594,7 +75629,8 @@ ${describeRewrites(prepared.rewrites)}
|
|
|
75594
75629
|
);
|
|
75595
75630
|
process.exit(2);
|
|
75596
75631
|
}
|
|
75597
|
-
|
|
75632
|
+
const advisories = (validation.warnings ?? []).filter((w) => w.code !== "ORPHAN_NODE");
|
|
75633
|
+
for (const w of [...advisories, ...await outputRatioWarningsFor(parsed, filePath)]) {
|
|
75598
75634
|
process.stdout.write(`[warn] ${w.code}: ${w.message}
|
|
75599
75635
|
`);
|
|
75600
75636
|
}
|
|
@@ -76062,7 +76098,7 @@ var rerunCommand = defineCommand140({
|
|
|
76062
76098
|
},
|
|
76063
76099
|
fresh: { type: "boolean", default: false, description: "Start a new run id instead of resuming an interrupted one" },
|
|
76064
76100
|
regenerate: { type: "string", description: "Comma-separated node ids to force fresh this run" },
|
|
76065
|
-
concurrency: { type: "string", description: "Max nodes
|
|
76101
|
+
concurrency: { type: "string", description: "Max nodes running at once" }
|
|
76066
76102
|
},
|
|
76067
76103
|
async run({ args: args8 }) {
|
|
76068
76104
|
process.stderr.write("[deprecated] `baker canvas rerun <slug>` is now `baker canvas run --slug <slug>`.\n");
|
|
@@ -81345,6 +81381,7 @@ async function readViewer(root, adSet) {
|
|
|
81345
81381
|
}
|
|
81346
81382
|
var MARKET_ADS = 40;
|
|
81347
81383
|
var MARKET_FALLBACK_ADS = 15;
|
|
81384
|
+
var MARKET_SEARCH_MS = 1e4;
|
|
81348
81385
|
function marketQuery(companyDoc) {
|
|
81349
81386
|
const prose = companyDoc.split("\n").filter((line) => line.trim() && !line.startsWith("#")).join(" ").replace(/\s+/g, " ");
|
|
81350
81387
|
return prose.slice(0, 240);
|
|
@@ -81352,7 +81389,14 @@ function marketQuery(companyDoc) {
|
|
|
81352
81389
|
async function readMarket(root) {
|
|
81353
81390
|
const query = marketQuery(await readFile36(path44.join(root, "COMPANY.md"), "utf8").catch(() => ""));
|
|
81354
81391
|
if (!query) return null;
|
|
81355
|
-
const search = (body) => apiPost("/api/ad-library/winners/search", body
|
|
81392
|
+
const search = (body) => apiPost("/api/ad-library/winners/search", body, {
|
|
81393
|
+
timeoutMs: MARKET_SEARCH_MS
|
|
81394
|
+
}).catch((err) => {
|
|
81395
|
+
if (err instanceof ApiError && err.code === "TIMEOUT") {
|
|
81396
|
+
throw new Error("the ad library did not answer in time, so competitors' claims are left out");
|
|
81397
|
+
}
|
|
81398
|
+
throw err;
|
|
81399
|
+
});
|
|
81356
81400
|
const followed = await search(
|
|
81357
81401
|
buildSearchBody({ scope: "followed", platform: "meta", limit: MARKET_ADS, maxPerAdvertiser: 8 })
|
|
81358
81402
|
);
|
|
@@ -81450,7 +81494,7 @@ function briefHints(parts) {
|
|
|
81450
81494
|
hints2.push(`Ideas ready to build: ${parts.buildNext.join(", ")} (\`baker creatives make <idea>\`).`);
|
|
81451
81495
|
} else {
|
|
81452
81496
|
hints2.push(
|
|
81453
|
-
|
|
81497
|
+
`Write 4-8 ideas in src/creatives/_ideas/<idea>.md (who, message, evidence, awareness, angle, format, job, why), then \`baker creatives ideas\`. awareness: ${AWARENESS_STAGES.join(" | ")}. angle: ${IDEA_ANGLES.join(", ")}. format: ${IDEA_FORMATS.join(", ")}.`
|
|
81454
81498
|
);
|
|
81455
81499
|
}
|
|
81456
81500
|
return hints2;
|
|
@@ -81953,7 +81997,7 @@ var learnCommand = defineCommand158({
|
|
|
81953
81997
|
|
|
81954
81998
|
// src/commands/creatives/make.ts
|
|
81955
81999
|
import { execFile as execFile3 } from "child_process";
|
|
81956
|
-
import { mkdtemp as mkdtemp2, readFile as readFile38, rm as rm7, writeFile as writeFile24 } from "fs/promises";
|
|
82000
|
+
import { mkdtemp as mkdtemp2, readFile as readFile38, rm as rm7, stat as stat7, writeFile as writeFile24 } from "fs/promises";
|
|
81957
82001
|
import { tmpdir as tmpdir3 } from "os";
|
|
81958
82002
|
import path46 from "path";
|
|
81959
82003
|
import { promisify as promisify3 } from "util";
|
|
@@ -82013,11 +82057,11 @@ function lastJsonObject(stdout) {
|
|
|
82013
82057
|
}
|
|
82014
82058
|
return null;
|
|
82015
82059
|
}
|
|
82016
|
-
async function baker(args8) {
|
|
82060
|
+
async function baker(args8, signal) {
|
|
82017
82061
|
const entry = process.argv[1];
|
|
82018
82062
|
const [file, argv] = entry ? [process.execPath, [...process.execArgv, entry, ...args8]] : ["baker", args8];
|
|
82019
82063
|
try {
|
|
82020
|
-
const { stdout } = await run2(file, argv, { maxBuffer: 32 * 1024 * 1024 });
|
|
82064
|
+
const { stdout } = await run2(file, argv, { maxBuffer: 32 * 1024 * 1024, ...signal ? { signal } : {} });
|
|
82021
82065
|
return lastJsonObject(stdout) ?? { ok: false, error: { code: "INTERNAL_ERROR", message: "no answer" } };
|
|
82022
82066
|
} catch (err) {
|
|
82023
82067
|
const { stdout = "", stderr = "" } = err;
|
|
@@ -82051,8 +82095,17 @@ async function findCandidates(searches, deps) {
|
|
|
82051
82095
|
}
|
|
82052
82096
|
return [];
|
|
82053
82097
|
}
|
|
82054
|
-
|
|
82098
|
+
var candidateOf = (c) => ({
|
|
82099
|
+
adId: String(c.ad_id),
|
|
82100
|
+
platform: asPlatform(c.platform),
|
|
82101
|
+
...c.advertiser_id ? { advertiserId: c.advertiser_id } : {}
|
|
82102
|
+
});
|
|
82103
|
+
async function pickReference(root, searches, deps = liveReferenceDeps(root), prepare) {
|
|
82055
82104
|
const candidates = (await findCandidates(searches, deps)).slice(0, FITS_TRIED);
|
|
82105
|
+
const first = candidates[0];
|
|
82106
|
+
const stop = new AbortController();
|
|
82107
|
+
const building = first && prepare ? prepare(candidateOf(first), stop.signal) : void 0;
|
|
82108
|
+
void building?.catch(() => void 0);
|
|
82056
82109
|
const fits = await Promise.all(candidates.map((c) => deps.fit(asPlatform(c.platform), String(c.ad_id))));
|
|
82057
82110
|
let unchecked = null;
|
|
82058
82111
|
let checked = 0;
|
|
@@ -82063,15 +82116,16 @@ async function pickReference(root, searches, deps = liveReferenceDeps(root)) {
|
|
|
82063
82116
|
else checked += 1;
|
|
82064
82117
|
if (!(fit.ok && fitsIdea(fit.fit))) continue;
|
|
82065
82118
|
const layers = fit.fit.why_it_wins;
|
|
82119
|
+
if (index > 0) stop.abort();
|
|
82066
82120
|
return {
|
|
82067
|
-
|
|
82068
|
-
platform: asPlatform(candidate.platform),
|
|
82069
|
-
...candidate.advertiser_id ? { advertiserId: candidate.advertiser_id } : {},
|
|
82121
|
+
...candidateOf(candidate),
|
|
82070
82122
|
why: [layers.disguise, layers.trigger, layers.logic].filter(Boolean).join("; "),
|
|
82071
|
-
tried: index + 1
|
|
82123
|
+
tried: index + 1,
|
|
82124
|
+
...building ? index === 0 ? { prepared: building } : { discarded: building } : {}
|
|
82072
82125
|
};
|
|
82073
82126
|
}
|
|
82074
|
-
|
|
82127
|
+
stop.abort();
|
|
82128
|
+
return { ...noReference(candidates.length, checked, unchecked), ...building ? { discarded: building } : {} };
|
|
82075
82129
|
}
|
|
82076
82130
|
function noReference(found, checked, unchecked) {
|
|
82077
82131
|
if (found > 0 && checked === 0 && unchecked) {
|
|
@@ -82087,6 +82141,18 @@ function noReference(found, checked, unchecked) {
|
|
|
82087
82141
|
fix: "Change the idea's format to another container (`baker creatives ideas --full` lists them) and run make again, or pass --reference <adId> for one you chose. Do not stop the batch: build the other ideas."
|
|
82088
82142
|
};
|
|
82089
82143
|
}
|
|
82144
|
+
function alreadyWritten(promptJson, slug) {
|
|
82145
|
+
if (promptJson === null || promptJson === void 0) return null;
|
|
82146
|
+
try {
|
|
82147
|
+
if (unwrittenProblems(readAdSpec(promptJson)).length > 0) return null;
|
|
82148
|
+
} catch {
|
|
82149
|
+
}
|
|
82150
|
+
return {
|
|
82151
|
+
code: "ALREADY_MADE",
|
|
82152
|
+
message: `"${slug}" is already made and its ad is written: building it again would replace that ad with placeholders.`,
|
|
82153
|
+
fix: `To change this ad, edit src/creatives/${slug}/prompt.json and run \`baker canvas run\` on it. For another ad of the same idea, run make again with --slug <new-slug>.`
|
|
82154
|
+
};
|
|
82155
|
+
}
|
|
82090
82156
|
var flag = (value2) => typeof value2 === "string" && value2 ? value2 : void 0;
|
|
82091
82157
|
async function loadIdea(root, ideaId) {
|
|
82092
82158
|
const { ideas, unreadable } = await readIdeas(root);
|
|
@@ -82139,24 +82205,40 @@ async function scaffoldIdea(root, idea, args8, slug, temperature) {
|
|
|
82139
82205
|
reference: null
|
|
82140
82206
|
};
|
|
82141
82207
|
}
|
|
82142
|
-
const
|
|
82208
|
+
const onReference = (c, signal) => baker(
|
|
82209
|
+
[
|
|
82210
|
+
"canvas",
|
|
82211
|
+
"scaffold-static-ad",
|
|
82212
|
+
"--source-ad-id",
|
|
82213
|
+
c.adId,
|
|
82214
|
+
"--source-platform",
|
|
82215
|
+
c.platform,
|
|
82216
|
+
...c.advertiserId ? ["--source-advertiser-id", c.advertiserId] : [],
|
|
82217
|
+
"--slug",
|
|
82218
|
+
slug,
|
|
82219
|
+
"--title",
|
|
82220
|
+
idea.message.slice(0, 120),
|
|
82221
|
+
...viewerFlags
|
|
82222
|
+
],
|
|
82223
|
+
signal
|
|
82224
|
+
);
|
|
82225
|
+
const dir = path46.join(root, "src", "creatives", slug);
|
|
82226
|
+
const fresh = !await stat7(dir).catch(() => null);
|
|
82227
|
+
const reference = args8.reference ? { adId: args8.reference, platform: asPlatform(args8.platform), why: "chosen by hand", tried: 0 } : args8.fromIdea ? { code: "FROM_IDEA", message: "Asked to start from the idea." } : await pickReference(
|
|
82228
|
+
root,
|
|
82229
|
+
referenceSearchesFor(idea, temperature).map(buildSearchBody),
|
|
82230
|
+
void 0,
|
|
82231
|
+
fresh ? onReference : void 0
|
|
82232
|
+
);
|
|
82233
|
+
if ("discarded" in reference && reference.discarded) {
|
|
82234
|
+
await reference.discarded.catch(() => void 0);
|
|
82235
|
+
await rm7(dir, { recursive: true, force: true });
|
|
82236
|
+
}
|
|
82143
82237
|
if ("code" in reference) {
|
|
82144
82238
|
return { scaffold: await scaffoldFromIdea(idea, slug, viewerFlags), reference: null, fromIdea: reference.message };
|
|
82145
82239
|
}
|
|
82146
|
-
const
|
|
82147
|
-
|
|
82148
|
-
"scaffold-static-ad",
|
|
82149
|
-
"--source-ad-id",
|
|
82150
|
-
reference.adId,
|
|
82151
|
-
"--source-platform",
|
|
82152
|
-
reference.platform,
|
|
82153
|
-
...reference.advertiserId ? ["--source-advertiser-id", reference.advertiserId] : [],
|
|
82154
|
-
"--slug",
|
|
82155
|
-
slug,
|
|
82156
|
-
"--title",
|
|
82157
|
-
idea.message.slice(0, 120),
|
|
82158
|
-
...viewerFlags
|
|
82159
|
-
]);
|
|
82240
|
+
const prepared = "prepared" in reference ? await reference.prepared?.catch(() => null) : null;
|
|
82241
|
+
const scaffold = prepared?.ok === true ? prepared : await onReference(reference);
|
|
82160
82242
|
return { scaffold, reference };
|
|
82161
82243
|
}
|
|
82162
82244
|
async function scaffoldFromIdea(idea, slug, viewerFlags) {
|
|
@@ -82253,6 +82335,7 @@ function makeEnvelope(made) {
|
|
|
82253
82335
|
`Rewrite before running: ${made.unsourcedCopy.map((l) => JSON.stringify(l)).join(", ")} claim a figure nothing the company wrote holds (the reference's promise, not ours).`
|
|
82254
82336
|
] : [],
|
|
82255
82337
|
`Write the copy lines and the scene in src/creatives/${made.slug}/prompt.json${made.reference ? ": the drafted lines are the reference's, so keep one only if the Knowledge says it (badges, ratings and guarantees too)" : ""}. Say the message in the customer's words${quote ? ` ("${quote.slice(0, 80)}")` : ""}; keep \`message\` as it is.`,
|
|
82338
|
+
SPEC_SHAPES_HINT,
|
|
82256
82339
|
`Then: baker canvas run ${made.canvasPath} (it validates and asks the viewer itself: nothing to run before it).`,
|
|
82257
82340
|
// The scaffold's own next steps name a separate validate; the run does it (dev, Oct 2026: five validates before one run).
|
|
82258
82341
|
...made.scaffoldHints.filter((h) => !/canvas (?:validate|viewer-check)/.test(h)).slice(0, 4)
|
|
@@ -82267,6 +82350,18 @@ var makeCommand = defineCommand159({
|
|
|
82267
82350
|
const opts = makeArgsOf(args8);
|
|
82268
82351
|
const { idea, check } = await loadIdea(root, String(args8.idea));
|
|
82269
82352
|
const slug = opts.slug ?? idea.id;
|
|
82353
|
+
const written = await readFile38(path46.join(root, "src", "creatives", slug, "prompt.json"), "utf8").then(
|
|
82354
|
+
(text3) => {
|
|
82355
|
+
try {
|
|
82356
|
+
return JSON.parse(text3);
|
|
82357
|
+
} catch {
|
|
82358
|
+
return {};
|
|
82359
|
+
}
|
|
82360
|
+
},
|
|
82361
|
+
(err) => err.code === "ENOENT" ? null : {}
|
|
82362
|
+
);
|
|
82363
|
+
const refused = alreadyWritten(written, slug);
|
|
82364
|
+
if (refused) fail6(refused);
|
|
82270
82365
|
const temperature = await viewerTemperature(root, opts.adset, idea.awareness);
|
|
82271
82366
|
const { scaffold, reference, fromIdea } = await scaffoldIdea(root, idea, opts, slug, temperature);
|
|
82272
82367
|
if (scaffold.ok !== true) fail6(scaffoldFailure(scaffold));
|
|
@@ -84030,7 +84125,7 @@ import { readdir as readdir19, readFile as readFile42 } from "fs/promises";
|
|
|
84030
84125
|
import path48 from "path";
|
|
84031
84126
|
|
|
84032
84127
|
// src/commands/landing/import-graph.ts
|
|
84033
|
-
import { readdir as readdir18, readFile as readFile41, stat as
|
|
84128
|
+
import { readdir as readdir18, readFile as readFile41, stat as stat8 } from "fs/promises";
|
|
84034
84129
|
import path47 from "path";
|
|
84035
84130
|
var SOURCE_EXT = /\.(astro|ts|tsx|js|jsx|mjs|cjs|vue|svelte)$/;
|
|
84036
84131
|
var RESOLVE_CANDIDATES = [
|
|
@@ -84050,7 +84145,7 @@ var IMPORT_RE = /(?<![A-Za-z0-9_$])(?:import|export)\s*(?:[\s\S]*?\bfrom\s*)?["'
|
|
|
84050
84145
|
var DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*["']([^"']+)["']\s*\)/g;
|
|
84051
84146
|
async function isFile(p) {
|
|
84052
84147
|
try {
|
|
84053
|
-
return (await
|
|
84148
|
+
return (await stat8(p)).isFile();
|
|
84054
84149
|
} catch {
|
|
84055
84150
|
return false;
|
|
84056
84151
|
}
|
|
@@ -84182,7 +84277,7 @@ async function readForms(root, slug) {
|
|
|
84182
84277
|
|
|
84183
84278
|
// src/commands/experiment/fold.ts
|
|
84184
84279
|
import { statSync } from "fs";
|
|
84185
|
-
import { cp as cp3, mkdir as mkdir15, readdir as readdir20, readFile as readFile43, rm as rm8, stat as
|
|
84280
|
+
import { cp as cp3, mkdir as mkdir15, readdir as readdir20, readFile as readFile43, rm as rm8, stat as stat9, writeFile as writeFile25 } from "fs/promises";
|
|
84186
84281
|
import path50 from "path";
|
|
84187
84282
|
|
|
84188
84283
|
// ../api/src/experiments/variants.ts
|
|
@@ -84249,7 +84344,7 @@ function posix2(p) {
|
|
|
84249
84344
|
}
|
|
84250
84345
|
async function isDir(p) {
|
|
84251
84346
|
try {
|
|
84252
|
-
return (await
|
|
84347
|
+
return (await stat9(p)).isDirectory();
|
|
84253
84348
|
} catch {
|
|
84254
84349
|
return false;
|
|
84255
84350
|
}
|
|
@@ -91651,7 +91746,7 @@ function cropSprite(input, region) {
|
|
|
91651
91746
|
|
|
91652
91747
|
// src/lib/image/io.ts
|
|
91653
91748
|
import { randomBytes } from "crypto";
|
|
91654
|
-
import { glob as fsGlob, readFile as readFile46, rename as rename2, stat as
|
|
91749
|
+
import { glob as fsGlob, readFile as readFile46, rename as rename2, stat as stat10, writeFile as writeFile26 } from "fs/promises";
|
|
91655
91750
|
import { dirname as dirname2, extname as extname3, join as join5, resolve as resolve4 } from "path";
|
|
91656
91751
|
var REMOTE_RE = /^https?:\/\//i;
|
|
91657
91752
|
var GLOB_RE = /[*?[\]{}]/;
|
|
@@ -91688,7 +91783,7 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
91688
91783
|
}
|
|
91689
91784
|
async function isDirectory(path68) {
|
|
91690
91785
|
try {
|
|
91691
|
-
const s = await
|
|
91786
|
+
const s = await stat10(path68);
|
|
91692
91787
|
return s.isDirectory();
|
|
91693
91788
|
} catch {
|
|
91694
91789
|
return false;
|
|
@@ -95146,7 +95241,7 @@ Full guide: __tooling__/docs/tools/baker/images.md`
|
|
|
95146
95241
|
import { defineCommand as defineCommand226 } from "citty";
|
|
95147
95242
|
|
|
95148
95243
|
// src/commands/landing/critique.ts
|
|
95149
|
-
import { readdir as readdir22, readFile as readFile48, stat as
|
|
95244
|
+
import { readdir as readdir22, readFile as readFile48, stat as stat12 } from "fs/promises";
|
|
95150
95245
|
import path55 from "path";
|
|
95151
95246
|
import { defineCommand as defineCommand213 } from "citty";
|
|
95152
95247
|
|
|
@@ -96357,7 +96452,7 @@ async function writeCritiqueSnapshot(projectRoot, snapshot) {
|
|
|
96357
96452
|
}
|
|
96358
96453
|
|
|
96359
96454
|
// src/commands/landing/source-version.ts
|
|
96360
|
-
import { readdir as readdir21, readFile as readFile47, stat as
|
|
96455
|
+
import { readdir as readdir21, readFile as readFile47, stat as stat11 } from "fs/promises";
|
|
96361
96456
|
import path54 from "path";
|
|
96362
96457
|
var CRITIQUED_ROOTS = ["src/pages/", "src/components/"];
|
|
96363
96458
|
async function landingSourceRelPaths(root, slug) {
|
|
@@ -96405,7 +96500,7 @@ async function computeLegacyLandingSourceSha(landingDir) {
|
|
|
96405
96500
|
}
|
|
96406
96501
|
async function isFile2(p) {
|
|
96407
96502
|
try {
|
|
96408
|
-
return (await
|
|
96503
|
+
return (await stat11(p)).isFile();
|
|
96409
96504
|
} catch {
|
|
96410
96505
|
return false;
|
|
96411
96506
|
}
|
|
@@ -96583,7 +96678,7 @@ function present(f) {
|
|
|
96583
96678
|
}
|
|
96584
96679
|
async function isDir2(p) {
|
|
96585
96680
|
try {
|
|
96586
|
-
return (await
|
|
96681
|
+
return (await stat12(p)).isDirectory();
|
|
96587
96682
|
} catch {
|
|
96588
96683
|
return false;
|
|
96589
96684
|
}
|
|
@@ -99901,7 +99996,7 @@ Full guide: __tooling__/docs/tools/baker/landing.md`
|
|
|
99901
99996
|
|
|
99902
99997
|
// src/commands/landing/variant.ts
|
|
99903
99998
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
99904
|
-
import { mkdir as mkdir20, readdir as readdir23, readFile as readFile49, stat as
|
|
99999
|
+
import { mkdir as mkdir20, readdir as readdir23, readFile as readFile49, stat as stat13, writeFile as writeFile32 } from "fs/promises";
|
|
99905
100000
|
import path63 from "path";
|
|
99906
100001
|
import { defineCommand as defineCommand225 } from "citty";
|
|
99907
100002
|
registerSchema({
|
|
@@ -99953,14 +100048,14 @@ function fail11(code, message, fix) {
|
|
|
99953
100048
|
}
|
|
99954
100049
|
async function isDir3(p) {
|
|
99955
100050
|
try {
|
|
99956
|
-
return (await
|
|
100051
|
+
return (await stat13(p)).isDirectory();
|
|
99957
100052
|
} catch {
|
|
99958
100053
|
return false;
|
|
99959
100054
|
}
|
|
99960
100055
|
}
|
|
99961
100056
|
async function exists2(p) {
|
|
99962
100057
|
try {
|
|
99963
|
-
await
|
|
100058
|
+
await stat13(p);
|
|
99964
100059
|
return true;
|
|
99965
100060
|
} catch {
|
|
99966
100061
|
return false;
|
|
@@ -108029,7 +108124,7 @@ var groupCommand2 = defineCommand295({
|
|
|
108029
108124
|
});
|
|
108030
108125
|
|
|
108031
108126
|
// src/commands/videos/ingest.ts
|
|
108032
|
-
import { mkdtemp as mkdtemp4, rm as rm10, stat as
|
|
108127
|
+
import { mkdtemp as mkdtemp4, rm as rm10, stat as stat14 } from "fs/promises";
|
|
108033
108128
|
import { tmpdir as tmpdir5 } from "os";
|
|
108034
108129
|
import path67 from "path";
|
|
108035
108130
|
import { defineCommand as defineCommand296 } from "citty";
|
|
@@ -108302,7 +108397,7 @@ async function downloadThenIngest(args8, country) {
|
|
|
108302
108397
|
// we allow to fetch it cannot drift apart.
|
|
108303
108398
|
timeoutMs: downloadTimeoutMs(durationSeconds(probe.info))
|
|
108304
108399
|
});
|
|
108305
|
-
const stats = await
|
|
108400
|
+
const stats = await stat14(filePath);
|
|
108306
108401
|
if (stats.size > MAX_VIDEO_INGEST_BYTES) {
|
|
108307
108402
|
throw new ApiError(
|
|
108308
108403
|
"VALIDATION_ERROR",
|
|
@@ -108463,7 +108558,7 @@ var searchCommand6 = defineCommand298({
|
|
|
108463
108558
|
var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
108464
108559
|
|
|
108465
108560
|
// src/commands/videos/upload.ts
|
|
108466
|
-
import { stat as
|
|
108561
|
+
import { stat as stat15 } from "fs/promises";
|
|
108467
108562
|
import { basename as basename4 } from "path";
|
|
108468
108563
|
import { defineCommand as defineCommand299 } from "citty";
|
|
108469
108564
|
registerSchema({
|
|
@@ -108531,7 +108626,7 @@ var uploadCommand2 = defineCommand299({
|
|
|
108531
108626
|
const contentType = args8["content-type"] || detectVideoContentType(filePath);
|
|
108532
108627
|
const descriptionContext = args8.context;
|
|
108533
108628
|
if (args8["dry-run"]) {
|
|
108534
|
-
const fileStats = await
|
|
108629
|
+
const fileStats = await stat15(filePath);
|
|
108535
108630
|
const originalFilename = basename4(filePath);
|
|
108536
108631
|
writeJson({
|
|
108537
108632
|
ok: true,
|