@koda-sl/baker-cli 0.120.0-dev.3b02f951b → 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.
- package/README.md +0 -33
- package/dist/{chunk-AWSEBYP4.js → chunk-IWPAXJC3.js} +57 -243
- package/dist/chunk-IWPAXJC3.js.map +1 -0
- package/dist/cli.js +92 -412
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.d.ts +0 -30
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AWSEBYP4.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
BackendClient,
|
|
4
3
|
ELEVENLABS_MAX_MUSIC_LENGTH_MS,
|
|
5
4
|
IMAGE_GENERATE_MODELS,
|
|
6
5
|
LayerExecutionError,
|
|
7
6
|
MODEL_REGISTRY,
|
|
8
7
|
SEEDANCE_DURATIONS,
|
|
9
8
|
ValidationError,
|
|
10
|
-
collectAssetRefLikes,
|
|
11
9
|
createEngineFromEnv,
|
|
12
10
|
defaultRegistry,
|
|
13
11
|
describeFailureReason,
|
|
14
12
|
elementMentionKeywords,
|
|
15
13
|
generateCatalog,
|
|
16
|
-
isPersistedAssetRef,
|
|
17
|
-
requireCredentialsFromEnv,
|
|
18
14
|
resolveConcurrency,
|
|
19
|
-
sha256Hex,
|
|
20
|
-
ulid,
|
|
21
15
|
validateCanvasDeep
|
|
22
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-IWPAXJC3.js";
|
|
23
17
|
import {
|
|
24
18
|
csvOrJson,
|
|
25
19
|
daysAgoIso,
|
|
@@ -4670,11 +4664,11 @@ function rawTextEntries(value) {
|
|
|
4670
4664
|
const values = Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
|
|
4671
4665
|
return values.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim()).filter(Boolean);
|
|
4672
4666
|
}
|
|
4673
|
-
function rawFileEntries(
|
|
4674
|
-
if (typeof
|
|
4667
|
+
function rawFileEntries(path12) {
|
|
4668
|
+
if (typeof path12 !== "string" || path12.length === 0) {
|
|
4675
4669
|
return [];
|
|
4676
4670
|
}
|
|
4677
|
-
return readFileSync2(
|
|
4671
|
+
return readFileSync2(path12, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
4678
4672
|
}
|
|
4679
4673
|
function keywordEntries(args) {
|
|
4680
4674
|
const defaultMatch = typeof args["match-type"] === "string" ? args["match-type"].toUpperCase() : void 0;
|
|
@@ -4697,19 +4691,19 @@ function keywordEntries(args) {
|
|
|
4697
4691
|
}
|
|
4698
4692
|
return entries;
|
|
4699
4693
|
}
|
|
4700
|
-
function loadJsonFileArg(
|
|
4701
|
-
if (typeof
|
|
4694
|
+
function loadJsonFileArg(path12) {
|
|
4695
|
+
if (typeof path12 !== "string" || path12.length === 0) {
|
|
4702
4696
|
return {};
|
|
4703
4697
|
}
|
|
4704
4698
|
try {
|
|
4705
|
-
const parsed = JSON.parse(readFileSync2(
|
|
4699
|
+
const parsed = JSON.parse(readFileSync2(path12, "utf8"));
|
|
4706
4700
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
4707
|
-
failWriteValidation(`${
|
|
4701
|
+
failWriteValidation(`${path12} must contain a JSON object`);
|
|
4708
4702
|
}
|
|
4709
4703
|
return parsed;
|
|
4710
4704
|
} catch (err) {
|
|
4711
4705
|
if (err instanceof SyntaxError) {
|
|
4712
|
-
failWriteValidation(`${
|
|
4706
|
+
failWriteValidation(`${path12} is not valid JSON: ${err.message}`);
|
|
4713
4707
|
}
|
|
4714
4708
|
throw err;
|
|
4715
4709
|
}
|
|
@@ -4820,10 +4814,10 @@ async function stageUpdate(kind, customerId, target, payload) {
|
|
|
4820
4814
|
async function stageTarget(kind, customerId, target) {
|
|
4821
4815
|
await stageGoogleOp({ kind, customerId, target });
|
|
4822
4816
|
}
|
|
4823
|
-
async function draftAction(
|
|
4817
|
+
async function draftAction(path12, body) {
|
|
4824
4818
|
try {
|
|
4825
4819
|
const chatId = requireChatId();
|
|
4826
|
-
const response = await apiPost(
|
|
4820
|
+
const response = await apiPost(path12, { chatId, ...body });
|
|
4827
4821
|
writeJsonEnvelope(response);
|
|
4828
4822
|
} catch (err) {
|
|
4829
4823
|
handleGoogleError(err);
|
|
@@ -8578,19 +8572,19 @@ function failWriteValidation2(message) {
|
|
|
8578
8572
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
8579
8573
|
process.exit(1);
|
|
8580
8574
|
}
|
|
8581
|
-
function loadJsonFileArg2(
|
|
8582
|
-
if (typeof
|
|
8575
|
+
function loadJsonFileArg2(path12) {
|
|
8576
|
+
if (typeof path12 !== "string" || path12.length === 0) {
|
|
8583
8577
|
return {};
|
|
8584
8578
|
}
|
|
8585
8579
|
try {
|
|
8586
|
-
const parsed = JSON.parse(readFileSync6(
|
|
8580
|
+
const parsed = JSON.parse(readFileSync6(path12, "utf8"));
|
|
8587
8581
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
8588
|
-
failWriteValidation2(`${
|
|
8582
|
+
failWriteValidation2(`${path12} must contain a JSON object`);
|
|
8589
8583
|
}
|
|
8590
8584
|
return parsed;
|
|
8591
8585
|
} catch (err) {
|
|
8592
8586
|
if (err instanceof SyntaxError) {
|
|
8593
|
-
failWriteValidation2(`${
|
|
8587
|
+
failWriteValidation2(`${path12} is not valid JSON: ${err.message}`);
|
|
8594
8588
|
}
|
|
8595
8589
|
throw err;
|
|
8596
8590
|
}
|
|
@@ -8675,15 +8669,15 @@ function parseLocaleFlag(value) {
|
|
|
8675
8669
|
}
|
|
8676
8670
|
return { language: match[1], country: match[2].toUpperCase() };
|
|
8677
8671
|
}
|
|
8678
|
-
function loadTargetingFileArg(
|
|
8679
|
-
if (typeof
|
|
8672
|
+
function loadTargetingFileArg(path12) {
|
|
8673
|
+
if (typeof path12 !== "string" || path12.length === 0) {
|
|
8680
8674
|
return void 0;
|
|
8681
8675
|
}
|
|
8682
|
-
const parsed = loadJsonFileArg2(
|
|
8676
|
+
const parsed = loadJsonFileArg2(path12);
|
|
8683
8677
|
const criteria = parsed.targetingCriteria ?? parsed;
|
|
8684
8678
|
if (!criteria.include) {
|
|
8685
8679
|
failWriteValidation2(
|
|
8686
|
-
`${
|
|
8680
|
+
`${path12} must contain targeting criteria with an "include" block (see baker schema ads.linkedin.campaigns.create)`
|
|
8687
8681
|
);
|
|
8688
8682
|
}
|
|
8689
8683
|
return criteria;
|
|
@@ -8718,14 +8712,14 @@ function parseCsvLine(line) {
|
|
|
8718
8712
|
cells.push(current);
|
|
8719
8713
|
return cells.map((cell) => cell.trim());
|
|
8720
8714
|
}
|
|
8721
|
-
function parseListFileArg(
|
|
8722
|
-
if (typeof
|
|
8715
|
+
function parseListFileArg(path12, maxRows) {
|
|
8716
|
+
if (typeof path12 !== "string" || path12.length === 0) {
|
|
8723
8717
|
return void 0;
|
|
8724
8718
|
}
|
|
8725
|
-
const raw = readFileSync6(
|
|
8719
|
+
const raw = readFileSync6(path12, "utf8");
|
|
8726
8720
|
const lines = raw.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
8727
8721
|
if (lines.length < 2) {
|
|
8728
|
-
failWriteValidation2(`${
|
|
8722
|
+
failWriteValidation2(`${path12} needs a header row and at least one data row`);
|
|
8729
8723
|
}
|
|
8730
8724
|
const columns = parseCsvLine(lines[0]).map((column) => column.trim());
|
|
8731
8725
|
const rows = [];
|
|
@@ -8744,7 +8738,7 @@ function parseListFileArg(path14, maxRows) {
|
|
|
8744
8738
|
}
|
|
8745
8739
|
}
|
|
8746
8740
|
if (rows.length > maxRows) {
|
|
8747
|
-
failWriteValidation2(`${
|
|
8741
|
+
failWriteValidation2(`${path12} has ${rows.length} rows \u2014 the inline limit is ${maxRows}. Split the list.`);
|
|
8748
8742
|
}
|
|
8749
8743
|
return { columns, rows };
|
|
8750
8744
|
}
|
|
@@ -10827,11 +10821,11 @@ var updateStatusSchema = z9.enum(UPDATE_STATUSES);
|
|
|
10827
10821
|
function currencyMinimums2(currencyCode) {
|
|
10828
10822
|
return CURRENCY_MINIMUMS2[currencyCode] ?? DEFAULT_CURRENCY_MINIMUM2;
|
|
10829
10823
|
}
|
|
10830
|
-
function validateDailyBudgetFloor(money, ctx,
|
|
10824
|
+
function validateDailyBudgetFloor(money, ctx, path12) {
|
|
10831
10825
|
if (money?.currencyCode) {
|
|
10832
10826
|
const min = currencyMinimums2(money.currencyCode).dailyBudgetMin;
|
|
10833
10827
|
if (Number(money.amount) < min) {
|
|
10834
|
-
ctx.addIssue({ code: "custom", path:
|
|
10828
|
+
ctx.addIssue({ code: "custom", path: path12, message: `below the ${min} ${money.currencyCode} daily minimum` });
|
|
10835
10829
|
}
|
|
10836
10830
|
}
|
|
10837
10831
|
}
|
|
@@ -11319,19 +11313,19 @@ function failWriteValidation3(message) {
|
|
|
11319
11313
|
writeJsonEnvelope({ ok: false, error: { code: "VALIDATION_ERROR", message } });
|
|
11320
11314
|
process.exit(1);
|
|
11321
11315
|
}
|
|
11322
|
-
function loadJsonFileArg3(
|
|
11323
|
-
if (typeof
|
|
11316
|
+
function loadJsonFileArg3(path12) {
|
|
11317
|
+
if (typeof path12 !== "string" || path12.length === 0) {
|
|
11324
11318
|
return {};
|
|
11325
11319
|
}
|
|
11326
11320
|
try {
|
|
11327
|
-
const parsed = JSON.parse(readFileSync8(
|
|
11321
|
+
const parsed = JSON.parse(readFileSync8(path12, "utf8"));
|
|
11328
11322
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
11329
|
-
failWriteValidation3(`${
|
|
11323
|
+
failWriteValidation3(`${path12} must contain a JSON object`);
|
|
11330
11324
|
}
|
|
11331
11325
|
return parsed;
|
|
11332
11326
|
} catch (err) {
|
|
11333
11327
|
if (err instanceof SyntaxError) {
|
|
11334
|
-
failWriteValidation3(`${
|
|
11328
|
+
failWriteValidation3(`${path12} is not valid JSON: ${err.message}`);
|
|
11335
11329
|
}
|
|
11336
11330
|
throw err;
|
|
11337
11331
|
}
|
|
@@ -14394,7 +14388,7 @@ async function probeDuration(filePath) {
|
|
|
14394
14388
|
|
|
14395
14389
|
// src/commands/canvas/run.ts
|
|
14396
14390
|
import { readFile as readFile2 } from "fs/promises";
|
|
14397
|
-
import
|
|
14391
|
+
import path4 from "path";
|
|
14398
14392
|
import { defineCommand as defineCommand88 } from "citty";
|
|
14399
14393
|
|
|
14400
14394
|
// src/commands/canvas/placeholders.ts
|
|
@@ -14438,102 +14432,9 @@ function isResolvableRelative(value) {
|
|
|
14438
14432
|
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !path2.isAbsolute(value);
|
|
14439
14433
|
}
|
|
14440
14434
|
|
|
14441
|
-
// src/commands/canvas/run-record.ts
|
|
14442
|
-
import path3 from "path";
|
|
14443
|
-
var MAX_RUN_NODES = 200;
|
|
14444
|
-
var MAX_OUTPUTS_PER_NODE = 10;
|
|
14445
|
-
var MAX_FINAL_OUTPUTS = 10;
|
|
14446
|
-
var MAX_CREATIVE_SLUG_LENGTH = 100;
|
|
14447
|
-
function creativeSlugFromCanvasPath(filePath) {
|
|
14448
|
-
const normalized = filePath.split(path3.sep).join("/");
|
|
14449
|
-
const match = normalized.match(/(?:^|\/)src\/creatives\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\//);
|
|
14450
|
-
const slug = match?.[1] ?? null;
|
|
14451
|
-
return slug && slug.length <= MAX_CREATIVE_SLUG_LENGTH ? slug : null;
|
|
14452
|
-
}
|
|
14453
|
-
var OUTPUT_KINDS = /* @__PURE__ */ new Set(["image", "video", "audio", "json", "text", "font"]);
|
|
14454
|
-
function toRecordOutput(slot, value) {
|
|
14455
|
-
const refs = collectAssetRefLikes(value);
|
|
14456
|
-
const ref = refs.length === 1 ? refs[0] : null;
|
|
14457
|
-
if (!ref || !isPersistedAssetRef(ref)) return null;
|
|
14458
|
-
const kind = typeof ref.kind === "string" && OUTPUT_KINDS.has(ref.kind) ? ref.kind : null;
|
|
14459
|
-
if (!kind) return null;
|
|
14460
|
-
return {
|
|
14461
|
-
slot,
|
|
14462
|
-
kind,
|
|
14463
|
-
sha256: ref.sha256,
|
|
14464
|
-
url: ref.url,
|
|
14465
|
-
mime: ref.mime,
|
|
14466
|
-
width: typeof ref.width === "number" ? ref.width : void 0,
|
|
14467
|
-
height: typeof ref.height === "number" ? ref.height : void 0,
|
|
14468
|
-
durationMs: typeof ref.duration_ms === "number" ? ref.duration_ms : void 0
|
|
14469
|
-
};
|
|
14470
|
-
}
|
|
14471
|
-
function nodeOutputsToRecord(nodeOutputs) {
|
|
14472
|
-
const out = [];
|
|
14473
|
-
for (const [slot, value] of Object.entries(nodeOutputs)) {
|
|
14474
|
-
if (Array.isArray(value)) {
|
|
14475
|
-
value.forEach((item, i) => {
|
|
14476
|
-
const rec = toRecordOutput(`${slot}#${i}`, item);
|
|
14477
|
-
if (rec) out.push(rec);
|
|
14478
|
-
});
|
|
14479
|
-
} else {
|
|
14480
|
-
const rec = toRecordOutput(slot, value);
|
|
14481
|
-
if (rec) out.push(rec);
|
|
14482
|
-
}
|
|
14483
|
-
}
|
|
14484
|
-
return out.slice(0, MAX_OUTPUTS_PER_NODE);
|
|
14485
|
-
}
|
|
14486
|
-
function finalOutputsToRecord(output) {
|
|
14487
|
-
if (Array.isArray(output)) {
|
|
14488
|
-
return output.map((item, i) => toRecordOutput(`final#${i}`, item)).filter((rec2) => rec2 !== null).slice(0, MAX_FINAL_OUTPUTS);
|
|
14489
|
-
}
|
|
14490
|
-
const rec = toRecordOutput("final", output);
|
|
14491
|
-
return rec ? [rec] : [];
|
|
14492
|
-
}
|
|
14493
|
-
function buildRunRecord(result, meta) {
|
|
14494
|
-
const nodes = result.node_runs.slice(0, MAX_RUN_NODES).map((run) => ({
|
|
14495
|
-
nodeId: run.node_id,
|
|
14496
|
-
nodeType: run.node_type,
|
|
14497
|
-
cached: run.cached,
|
|
14498
|
-
credits: run.credits,
|
|
14499
|
-
durationMs: run.duration_ms,
|
|
14500
|
-
outputs: nodeOutputsToRecord(result.outputs_by_node[run.node_id] ?? {})
|
|
14501
|
-
}));
|
|
14502
|
-
const finalOutputs = finalOutputsToRecord(result.output);
|
|
14503
|
-
return {
|
|
14504
|
-
runId: result.run_id,
|
|
14505
|
-
creativeSlug: meta.creativeSlug,
|
|
14506
|
-
canvasPath: meta.canvasPath,
|
|
14507
|
-
canvasSha: meta.canvasSha,
|
|
14508
|
-
chatId: meta.chatId,
|
|
14509
|
-
status: "completed",
|
|
14510
|
-
stats: {
|
|
14511
|
-
totalNodes: result.stats.total_nodes,
|
|
14512
|
-
cachedNodes: result.stats.cached_nodes,
|
|
14513
|
-
totalCredits: result.stats.total_credits,
|
|
14514
|
-
durationMs: result.stats.duration_ms
|
|
14515
|
-
},
|
|
14516
|
-
nodes,
|
|
14517
|
-
finalOutputs: finalOutputs.length > 0 ? finalOutputs : void 0
|
|
14518
|
-
};
|
|
14519
|
-
}
|
|
14520
|
-
function buildFailedRunRecord(runId, errorMessage, meta) {
|
|
14521
|
-
return {
|
|
14522
|
-
runId,
|
|
14523
|
-
creativeSlug: meta.creativeSlug,
|
|
14524
|
-
canvasPath: meta.canvasPath,
|
|
14525
|
-
canvasSha: meta.canvasSha,
|
|
14526
|
-
chatId: meta.chatId,
|
|
14527
|
-
status: "failed",
|
|
14528
|
-
errorMessage: errorMessage.slice(0, 2e3),
|
|
14529
|
-
stats: { totalNodes: 0, cachedNodes: 0, totalCredits: 0, durationMs: 0 },
|
|
14530
|
-
nodes: []
|
|
14531
|
-
};
|
|
14532
|
-
}
|
|
14533
|
-
|
|
14534
14435
|
// src/commands/canvas/run-retention.ts
|
|
14535
14436
|
import { rm } from "fs/promises";
|
|
14536
|
-
import
|
|
14437
|
+
import path3 from "path";
|
|
14537
14438
|
function runDirsToPrune(entries, keep, currentRunId) {
|
|
14538
14439
|
const runs = entries.filter((e) => /^r_[0-9A-Za-z]+$/.test(e) && e !== currentRunId).sort();
|
|
14539
14440
|
if (keep <= 0) return runs;
|
|
@@ -14550,7 +14451,7 @@ async function pruneOldRuns(outputsDir, keep, currentRunId, log) {
|
|
|
14550
14451
|
const toPrune = runDirsToPrune(entries, keep, currentRunId);
|
|
14551
14452
|
if (toPrune.length === 0) return;
|
|
14552
14453
|
for (const dir of toPrune) {
|
|
14553
|
-
await rm(
|
|
14454
|
+
await rm(path3.join(outputsDir, dir), { recursive: true, force: true }).catch(
|
|
14554
14455
|
(e) => log(`[prune ] could not remove ${dir}: ${e.message}`)
|
|
14555
14456
|
);
|
|
14556
14457
|
}
|
|
@@ -14577,22 +14478,10 @@ var runCommand = defineCommand88({
|
|
|
14577
14478
|
"keep-runs": {
|
|
14578
14479
|
type: "string",
|
|
14579
14480
|
description: "After the run, prune old r_* run dirs, keeping the N newest (off by default)"
|
|
14580
|
-
},
|
|
14581
|
-
"remote-cache": {
|
|
14582
|
-
type: "string",
|
|
14583
|
-
description: "on | off \u2014 company-scoped remote cache + durable asset persistence (default on; env BAKER_CANVAS_REMOTE_CACHE)"
|
|
14584
|
-
},
|
|
14585
|
-
// citty consumes any `--no-<flag>` as a negation of `<flag>`, so the
|
|
14586
|
-
// opt-out spelling `--no-record` requires the flag to be named `record`
|
|
14587
|
-
// (a literal "no-record" arg would never receive a value).
|
|
14588
|
-
record: {
|
|
14589
|
-
type: "boolean",
|
|
14590
|
-
default: true,
|
|
14591
|
-
description: "Post the durable run-history record to Baker (disable with --no-record)"
|
|
14592
14481
|
}
|
|
14593
14482
|
},
|
|
14594
14483
|
async run({ args }) {
|
|
14595
|
-
const filePath =
|
|
14484
|
+
const filePath = path4.resolve(String(args.file));
|
|
14596
14485
|
const raw = await readFile2(filePath, "utf8");
|
|
14597
14486
|
let parsed;
|
|
14598
14487
|
try {
|
|
@@ -14603,7 +14492,7 @@ var runCommand = defineCommand88({
|
|
|
14603
14492
|
`);
|
|
14604
14493
|
process.exit(2);
|
|
14605
14494
|
}
|
|
14606
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
14495
|
+
parsed = resolveRelativeCanvasPaths(parsed, path4.dirname(filePath));
|
|
14607
14496
|
const pending = unsuppliedPlaceholderAssets(parsed);
|
|
14608
14497
|
if (pending.length > 0) {
|
|
14609
14498
|
process.stderr.write(
|
|
@@ -14623,26 +14512,16 @@ var runCommand = defineCommand88({
|
|
|
14623
14512
|
);
|
|
14624
14513
|
process.exit(2);
|
|
14625
14514
|
}
|
|
14626
|
-
const remoteCache = args["remote-cache"] !== void 0 ? String(args["remote-cache"]) !== "off" : void 0;
|
|
14627
14515
|
const engine = createEngineFromEnv({
|
|
14628
14516
|
cacheDir: args["cache-dir"] ? String(args["cache-dir"]) : void 0,
|
|
14629
14517
|
outputsDir: args["outputs-dir"] ? String(args["outputs-dir"]) : void 0,
|
|
14630
14518
|
log: (line) => process.stdout.write(`${line}
|
|
14631
|
-
`)
|
|
14632
|
-
remoteCache
|
|
14519
|
+
`)
|
|
14633
14520
|
});
|
|
14634
|
-
const runId = args["run-id"] ? String(args["run-id"]) : `r_${ulid()}`;
|
|
14635
|
-
const recordMeta = {
|
|
14636
|
-
creativeSlug: creativeSlugFromCanvasPath(filePath) ?? void 0,
|
|
14637
|
-
canvasPath: path5.relative(process.cwd(), filePath) || void 0,
|
|
14638
|
-
canvasSha: sha256Hex(Buffer.from(raw)),
|
|
14639
|
-
chatId: getEnv().BAKER_CHAT_ID || void 0
|
|
14640
|
-
};
|
|
14641
|
-
const record = args.record === false ? null : buildRecorder();
|
|
14642
14521
|
try {
|
|
14643
14522
|
const policy = args["cache-policy"] ?? "read_write";
|
|
14644
14523
|
const result = await engine.run(parsed, {
|
|
14645
|
-
run_id:
|
|
14524
|
+
run_id: args["run-id"] ? String(args["run-id"]) : void 0,
|
|
14646
14525
|
cache_policy: policy,
|
|
14647
14526
|
concurrency: resolveConcurrency(
|
|
14648
14527
|
// --concurrency wins; --parallel is the discoverable alias for the same bound.
|
|
@@ -14650,10 +14529,9 @@ var runCommand = defineCommand88({
|
|
|
14650
14529
|
process.env.BAKER_CANVAS_CONCURRENCY
|
|
14651
14530
|
)
|
|
14652
14531
|
});
|
|
14653
|
-
if (record) await record(buildRunRecord(result, recordMeta));
|
|
14654
14532
|
const keepRuns = args["keep-runs"] !== void 0 ? Number(args["keep-runs"]) : void 0;
|
|
14655
14533
|
if (keepRuns !== void 0 && Number.isFinite(keepRuns)) {
|
|
14656
|
-
const outputsDir = args["outputs-dir"] ?
|
|
14534
|
+
const outputsDir = args["outputs-dir"] ? path4.resolve(String(args["outputs-dir"])) : path4.resolve("canvas");
|
|
14657
14535
|
await pruneOldRuns(outputsDir, keepRuns, result.run_id, (line) => process.stdout.write(`${line}
|
|
14658
14536
|
`));
|
|
14659
14537
|
}
|
|
@@ -14681,7 +14559,6 @@ var runCommand = defineCommand88({
|
|
|
14681
14559
|
}
|
|
14682
14560
|
if (e instanceof LayerExecutionError) {
|
|
14683
14561
|
const failures = e.failures.map((f) => ({ node_id: f.nodeId, message: describeFailureReason(f.reason) }));
|
|
14684
|
-
if (record) await record(buildFailedRunRecord(runId, e.message, recordMeta));
|
|
14685
14562
|
process.stderr.write(
|
|
14686
14563
|
`${JSON.stringify({ ok: false, error: { code: "runtime", message: e.message, failures } }, null, 2)}
|
|
14687
14564
|
`
|
|
@@ -14689,30 +14566,16 @@ var runCommand = defineCommand88({
|
|
|
14689
14566
|
process.exit(1);
|
|
14690
14567
|
}
|
|
14691
14568
|
const msg = e instanceof Error ? e.message : String(e);
|
|
14692
|
-
if (record) await record(buildFailedRunRecord(runId, msg, recordMeta));
|
|
14693
14569
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "runtime", message: msg } }, null, 2)}
|
|
14694
14570
|
`);
|
|
14695
14571
|
process.exit(1);
|
|
14696
14572
|
}
|
|
14697
14573
|
}
|
|
14698
14574
|
});
|
|
14699
|
-
function buildRecorder() {
|
|
14700
|
-
return async (payload) => {
|
|
14701
|
-
try {
|
|
14702
|
-
const creds = requireCredentialsFromEnv();
|
|
14703
|
-
const client = new BackendClient({ baseUrl: creds.url, apiKey: creds.apiKey });
|
|
14704
|
-
await client.recordRun(payload);
|
|
14705
|
-
} catch (e) {
|
|
14706
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
14707
|
-
process.stderr.write(`[warn] run record not persisted (${msg})
|
|
14708
|
-
`);
|
|
14709
|
-
}
|
|
14710
|
-
};
|
|
14711
|
-
}
|
|
14712
14575
|
|
|
14713
14576
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
14714
|
-
import {
|
|
14715
|
-
import
|
|
14577
|
+
import { readFile as readFile3, writeFile } from "fs/promises";
|
|
14578
|
+
import path6 from "path";
|
|
14716
14579
|
import { defineCommand as defineCommand89 } from "citty";
|
|
14717
14580
|
|
|
14718
14581
|
// src/engine/scaffold/staticAd.ts
|
|
@@ -14898,106 +14761,18 @@ function staticAdReport(input, elementsInput, opts) {
|
|
|
14898
14761
|
};
|
|
14899
14762
|
}
|
|
14900
14763
|
|
|
14901
|
-
// src/commands/canvas/creative-definition.ts
|
|
14902
|
-
import path6 from "path";
|
|
14903
|
-
var PLATFORM_VALUES = ["meta", "google", "linkedin", "tiktok", "youtube", "x", "other"];
|
|
14904
|
-
var FORMAT_VALUES = ["1:1", "4:5", "9:16", "16:9", "1.91:1"];
|
|
14905
|
-
function titleFromSlug(slug) {
|
|
14906
|
-
const title = slug.split("-").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
14907
|
-
return title || slug;
|
|
14908
|
-
}
|
|
14909
|
-
function resolvePlatform(platform) {
|
|
14910
|
-
const value = platform?.trim();
|
|
14911
|
-
return value && PLATFORM_VALUES.includes(value) ? value : "meta";
|
|
14912
|
-
}
|
|
14913
|
-
function resolveFormats(aspect) {
|
|
14914
|
-
const value = aspect?.trim();
|
|
14915
|
-
return value && FORMAT_VALUES.includes(value) ? [value] : ["4:5"];
|
|
14916
|
-
}
|
|
14917
|
-
function referenceRelativePath(kind, ext) {
|
|
14918
|
-
const name = kind === "video" ? "source" : "original";
|
|
14919
|
-
return `references/${name}${ext}`;
|
|
14920
|
-
}
|
|
14921
|
-
function sourceExtension(source, isUrl, kind) {
|
|
14922
|
-
const raw = isUrl ? urlPathname(source) : source;
|
|
14923
|
-
const ext = path6.extname(raw).toLowerCase();
|
|
14924
|
-
if (/^\.[a-z0-9]{1,5}$/.test(ext)) return ext;
|
|
14925
|
-
return kind === "video" ? ".mp4" : ".jpg";
|
|
14926
|
-
}
|
|
14927
|
-
function urlPathname(source) {
|
|
14928
|
-
try {
|
|
14929
|
-
return new URL(source).pathname;
|
|
14930
|
-
} catch {
|
|
14931
|
-
return source;
|
|
14932
|
-
}
|
|
14933
|
-
}
|
|
14934
|
-
function describeBlueprintIntent(blueprint) {
|
|
14935
|
-
const intent = blueprint?.ad_intent;
|
|
14936
|
-
if (typeof intent === "string" && intent.trim()) return intent.trim();
|
|
14937
|
-
if (intent && typeof intent === "object") {
|
|
14938
|
-
const summary = intent.summary ?? intent.feeling;
|
|
14939
|
-
if (typeof summary === "string" && summary.trim()) return summary.trim();
|
|
14940
|
-
}
|
|
14941
|
-
return void 0;
|
|
14942
|
-
}
|
|
14943
|
-
function yamlScalar(value) {
|
|
14944
|
-
return JSON.stringify(value);
|
|
14945
|
-
}
|
|
14946
|
-
function buildCreativeDefinition(input) {
|
|
14947
|
-
const lines = ["---", `title: ${yamlScalar(input.title)}`, `kind: ${input.kind}`, `platform: ${input.platform}`];
|
|
14948
|
-
lines.push(`formats: [${input.formats.map(yamlScalar).join(", ")}]`);
|
|
14949
|
-
lines.push(`status: ${input.status ?? "draft"}`);
|
|
14950
|
-
if (input.sourceReferenceUrl) lines.push(`sourceReferenceUrl: ${yamlScalar(input.sourceReferenceUrl)}`);
|
|
14951
|
-
if (input.sourceAdvertiser) lines.push(`sourceAdvertiser: ${yamlScalar(input.sourceAdvertiser)}`);
|
|
14952
|
-
if (input.sourceKind) lines.push(`sourceKind: ${input.sourceKind}`);
|
|
14953
|
-
if (input.sourcePath) lines.push(`sourcePath: ${yamlScalar(input.sourcePath)}`);
|
|
14954
|
-
lines.push("---", "");
|
|
14955
|
-
lines.push(input.description?.trim() || `${input.title} \u2014 canvas-built ${input.kind} ad for ${input.platform}.`);
|
|
14956
|
-
lines.push("");
|
|
14957
|
-
return lines.join("\n");
|
|
14958
|
-
}
|
|
14959
|
-
|
|
14960
14764
|
// src/commands/canvas/scaffold-static-ad-paths.ts
|
|
14961
|
-
import
|
|
14962
|
-
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd()
|
|
14765
|
+
import path5 from "path";
|
|
14766
|
+
function resolveScaffoldStaticAdPaths(rawFile, out, cwd = process.cwd()) {
|
|
14963
14767
|
const file = rawFile.trim();
|
|
14964
14768
|
const imageIsUrl = /^https?:\/\//i.test(file);
|
|
14965
|
-
const imageSource = imageIsUrl ? file :
|
|
14966
|
-
const outPath = out ?
|
|
14967
|
-
const blueprintPath =
|
|
14968
|
-
|
|
14969
|
-
const definitionPath = creativeDir ? path7.join(creativeDir, "_definition.md") : null;
|
|
14970
|
-
const referencesDir = creativeDir ? path7.join(creativeDir, "references") : null;
|
|
14971
|
-
return { imageIsUrl, imageSource, outPath, blueprintPath, creativeDir, definitionPath, referencesDir };
|
|
14972
|
-
}
|
|
14973
|
-
var SCAFFOLD_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
14974
|
-
var SCAFFOLD_SLUG_MAX_LENGTH = 100;
|
|
14975
|
-
function isValidScaffoldSlug(slug) {
|
|
14976
|
-
return slug.length <= SCAFFOLD_SLUG_MAX_LENGTH && SCAFFOLD_SLUG_PATTERN.test(slug);
|
|
14769
|
+
const imageSource = imageIsUrl ? file : path5.resolve(cwd, file);
|
|
14770
|
+
const outPath = out ? path5.resolve(cwd, out) : imageIsUrl ? path5.join(cwd, "static-ad.canvas.json") : path5.join(path5.dirname(imageSource), "static-ad.canvas.json");
|
|
14771
|
+
const blueprintPath = path5.join(path5.dirname(outPath), "prompt.json");
|
|
14772
|
+
return { imageIsUrl, imageSource, outPath, blueprintPath };
|
|
14977
14773
|
}
|
|
14978
14774
|
|
|
14979
14775
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
14980
|
-
async function fileExists(target) {
|
|
14981
|
-
try {
|
|
14982
|
-
await access(target);
|
|
14983
|
-
return true;
|
|
14984
|
-
} catch {
|
|
14985
|
-
return false;
|
|
14986
|
-
}
|
|
14987
|
-
}
|
|
14988
|
-
async function copySourceIntoReferences(source, isUrl, referencesDir) {
|
|
14989
|
-
await mkdir(referencesDir, { recursive: true });
|
|
14990
|
-
const relPath = referenceRelativePath("image", sourceExtension(source, isUrl, "image"));
|
|
14991
|
-
const dest = path8.join(referencesDir, path8.basename(relPath));
|
|
14992
|
-
if (isUrl) {
|
|
14993
|
-
const res = await fetch(source);
|
|
14994
|
-
if (!res.ok) throw new Error(`failed to download source image (${res.status})`);
|
|
14995
|
-
await writeFile(dest, Buffer.from(await res.arrayBuffer()));
|
|
14996
|
-
} else {
|
|
14997
|
-
await cp(source, dest);
|
|
14998
|
-
}
|
|
14999
|
-
return relPath;
|
|
15000
|
-
}
|
|
15001
14776
|
function resolveModel(kind, preferred) {
|
|
15002
14777
|
const ids = Object.keys(MODEL_REGISTRY[kind]);
|
|
15003
14778
|
return ids.includes(preferred) ? preferred : ids[0] ?? preferred;
|
|
@@ -15157,16 +14932,6 @@ var scaffoldStaticAdCommand = defineCommand89({
|
|
|
15157
14932
|
file: { type: "positional", required: true, description: "Path or http(s) URL to the source/inspiration image" },
|
|
15158
14933
|
context: { type: "string", description: "Known provenance (advertiser, category, market) to ground the describe" },
|
|
15159
14934
|
out: { type: "string", description: "Output canvas path (default <image-dir>/static-ad.canvas.json)" },
|
|
15160
|
-
slug: {
|
|
15161
|
-
type: "string",
|
|
15162
|
-
description: "Creative slug \u2014 writes the canvas to src/creatives/<slug>/<slug>.canvas.json (repo convention)"
|
|
15163
|
-
},
|
|
15164
|
-
title: { type: "string", description: "Creative title for _definition.md (default: title-cased slug)" },
|
|
15165
|
-
platform: {
|
|
15166
|
-
type: "string",
|
|
15167
|
-
description: "Ad platform for _definition.md (meta|google|linkedin|tiktok|youtube|x|other; default meta)"
|
|
15168
|
-
},
|
|
15169
|
-
advertiser: { type: "string", description: "Source advertiser recorded in _definition.md" },
|
|
15170
14935
|
"describe-model": { type: "string", description: "Override the image_describe model id" },
|
|
15171
14936
|
"select-model": { type: "string", description: "Override the text_generate model id for element selection" },
|
|
15172
14937
|
"layout-model": { type: "string", description: "Override the text_generate model id for the layout pass" },
|
|
@@ -15175,21 +14940,10 @@ var scaffoldStaticAdCommand = defineCommand89({
|
|
|
15175
14940
|
"skip-font": { type: "boolean", description: "Skip the brand-font \u2192 type-specimen slot" }
|
|
15176
14941
|
},
|
|
15177
14942
|
async run({ args }) {
|
|
15178
|
-
const
|
|
15179
|
-
if (slug && !isValidScaffoldSlug(slug)) {
|
|
15180
|
-
process.stderr.write(
|
|
15181
|
-
`${JSON.stringify({ ok: false, error: { code: "invalid_slug", message: "--slug must be lowercase kebab (a-z, 0-9, hyphens), max 100 chars" } }, null, 2)}
|
|
15182
|
-
`
|
|
15183
|
-
);
|
|
15184
|
-
process.exit(2);
|
|
15185
|
-
}
|
|
15186
|
-
const { imageIsUrl, imageSource, outPath, blueprintPath, definitionPath, referencesDir } = resolveScaffoldStaticAdPaths(
|
|
14943
|
+
const { imageIsUrl, imageSource, outPath, blueprintPath } = resolveScaffoldStaticAdPaths(
|
|
15187
14944
|
String(args.file),
|
|
15188
|
-
args.out ? String(args.out) : void 0
|
|
15189
|
-
process.cwd(),
|
|
15190
|
-
slug
|
|
14945
|
+
args.out ? String(args.out) : void 0
|
|
15191
14946
|
);
|
|
15192
|
-
await mkdir(path8.dirname(outPath), { recursive: true });
|
|
15193
14947
|
const { describeModel, selectModel, layoutModel, genModel } = resolveModels(args);
|
|
15194
14948
|
const describeCanvas = buildDescribeCanvas(
|
|
15195
14949
|
imageSource,
|
|
@@ -15206,21 +14960,11 @@ var scaffoldStaticAdCommand = defineCommand89({
|
|
|
15206
14960
|
}
|
|
15207
14961
|
await writeFile(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
15208
14962
|
`, "utf8");
|
|
15209
|
-
let canvasImagePath = imageSource;
|
|
15210
|
-
let canvasImageIsUrl = imageIsUrl;
|
|
15211
|
-
let canvasBlueprintPath = blueprintPath;
|
|
15212
|
-
let sourceRelPath;
|
|
15213
|
-
if (referencesDir) {
|
|
15214
|
-
sourceRelPath = await copySourceIntoReferences(imageSource, imageIsUrl, referencesDir);
|
|
15215
|
-
canvasImagePath = sourceRelPath;
|
|
15216
|
-
canvasImageIsUrl = false;
|
|
15217
|
-
canvasBlueprintPath = "./prompt.json";
|
|
15218
|
-
}
|
|
15219
14963
|
const opts = {
|
|
15220
14964
|
genModel,
|
|
15221
|
-
imagePath:
|
|
15222
|
-
imageIsUrl
|
|
15223
|
-
blueprintPath
|
|
14965
|
+
imagePath: imageSource,
|
|
14966
|
+
imageIsUrl,
|
|
14967
|
+
blueprintPath,
|
|
15224
14968
|
aspectRatio: args.aspect ? String(args.aspect) : void 0,
|
|
15225
14969
|
includeFont: !args["skip-font"]
|
|
15226
14970
|
};
|
|
@@ -15242,31 +14986,12 @@ var scaffoldStaticAdCommand = defineCommand89({
|
|
|
15242
14986
|
}
|
|
15243
14987
|
await writeFile(outPath, `${JSON.stringify(canvas, null, 2)}
|
|
15244
14988
|
`, "utf8");
|
|
15245
|
-
if (definitionPath && !await fileExists(definitionPath)) {
|
|
15246
|
-
await writeFile(
|
|
15247
|
-
definitionPath,
|
|
15248
|
-
buildCreativeDefinition({
|
|
15249
|
-
title: args.title ? String(args.title) : titleFromSlug(slug ?? ""),
|
|
15250
|
-
kind: "static",
|
|
15251
|
-
platform: resolvePlatform(args.platform ? String(args.platform) : void 0),
|
|
15252
|
-
formats: resolveFormats(args.aspect ? String(args.aspect) : report.aspect_ratio),
|
|
15253
|
-
sourceReferenceUrl: imageIsUrl ? imageSource : void 0,
|
|
15254
|
-
sourceAdvertiser: args.advertiser ? String(args.advertiser) : args.context ? String(args.context) : void 0,
|
|
15255
|
-
sourceKind: "image",
|
|
15256
|
-
sourcePath: sourceRelPath,
|
|
15257
|
-
description: describeBlueprintIntent(blueprint)
|
|
15258
|
-
}),
|
|
15259
|
-
"utf8"
|
|
15260
|
-
);
|
|
15261
|
-
}
|
|
15262
14989
|
process.stdout.write(
|
|
15263
14990
|
`${JSON.stringify(
|
|
15264
14991
|
{
|
|
15265
14992
|
ok: true,
|
|
15266
14993
|
canvas_path: outPath,
|
|
15267
14994
|
prompt_path: blueprintPath,
|
|
15268
|
-
definition_path: definitionPath ?? void 0,
|
|
15269
|
-
source_reference: sourceRelPath ?? void 0,
|
|
15270
14995
|
output: canvas.output,
|
|
15271
14996
|
models: { describe: describeModel, select: selectModel, layout: layoutModel, gen: opts.genModel },
|
|
15272
14997
|
aspect_ratio: report.aspect_ratio,
|
|
@@ -15277,7 +15002,7 @@ var scaffoldStaticAdCommand = defineCommand89({
|
|
|
15277
15002
|
run_estimated_credits: validation.estimatedCredits
|
|
15278
15003
|
},
|
|
15279
15004
|
checklist: {
|
|
15280
|
-
edit_prompt: `Edit ${
|
|
15005
|
+
edit_prompt: `Edit ${path6.basename(blueprintPath)} \u2014 it is the blueprint generated from your image; rewrite it into the ad you want (palette, copy, claims, subjects). It feeds the generator directly.`,
|
|
15281
15006
|
assets_to_supply: report.elements,
|
|
15282
15007
|
font_slot: report.includes_font ? "Drop a brand font at the [TODO] brandfont path, or delete the brandfont + type_ref nodes to skip it." : "skipped (--skip-font)",
|
|
15283
15008
|
note: "Replace every [TODO] ingest path with a real file, then `baker canvas validate` and `baker canvas run`. Running generates a billed image \u2014 it is not free."
|
|
@@ -15292,8 +15017,8 @@ var scaffoldStaticAdCommand = defineCommand89({
|
|
|
15292
15017
|
});
|
|
15293
15018
|
|
|
15294
15019
|
// src/commands/canvas/scaffold-video.ts
|
|
15295
|
-
import { cp
|
|
15296
|
-
import
|
|
15020
|
+
import { cp, mkdir, readFile as readFile6, writeFile as writeFile2 } from "fs/promises";
|
|
15021
|
+
import path9 from "path";
|
|
15297
15022
|
import { defineCommand as defineCommand90 } from "citty";
|
|
15298
15023
|
|
|
15299
15024
|
// src/engine/nodes/local/lib/sceneDetect.ts
|
|
@@ -18401,23 +18126,23 @@ function videoReport(input, elementsInput) {
|
|
|
18401
18126
|
|
|
18402
18127
|
// src/commands/canvas/composition-path.ts
|
|
18403
18128
|
import { existsSync as existsSync3 } from "fs";
|
|
18404
|
-
import
|
|
18129
|
+
import path7 from "path";
|
|
18405
18130
|
function resolveShippedCanvasDir(name, startDir, exists = existsSync3, maxDepth = 8) {
|
|
18406
|
-
const rel =
|
|
18131
|
+
const rel = path7.join("canvas", name);
|
|
18407
18132
|
let dir = startDir;
|
|
18408
18133
|
for (let i = 0; i < maxDepth; i++) {
|
|
18409
|
-
const candidate =
|
|
18410
|
-
if (exists(
|
|
18411
|
-
const parent =
|
|
18134
|
+
const candidate = path7.join(dir, rel);
|
|
18135
|
+
if (exists(path7.join(candidate, "meta.json"))) return candidate;
|
|
18136
|
+
const parent = path7.dirname(dir);
|
|
18412
18137
|
if (parent === dir) break;
|
|
18413
18138
|
dir = parent;
|
|
18414
18139
|
}
|
|
18415
|
-
return
|
|
18140
|
+
return path7.resolve(startDir, "../../../", rel);
|
|
18416
18141
|
}
|
|
18417
18142
|
|
|
18418
18143
|
// src/commands/canvas/gitignore.ts
|
|
18419
18144
|
import { appendFile, readFile as readFile5 } from "fs/promises";
|
|
18420
|
-
import
|
|
18145
|
+
import path8 from "path";
|
|
18421
18146
|
function missingGitignoreEntries(existing, entries) {
|
|
18422
18147
|
const present = new Set(
|
|
18423
18148
|
existing.split("\n").map((l) => l.trim().replace(/\/+$/, "")).filter((l) => l.length > 0 && !l.startsWith("#"))
|
|
@@ -18425,7 +18150,7 @@ function missingGitignoreEntries(existing, entries) {
|
|
|
18425
18150
|
return entries.filter((e) => !present.has(e.trim().replace(/\/+$/, "")));
|
|
18426
18151
|
}
|
|
18427
18152
|
async function ensureGitignore(dir, entries) {
|
|
18428
|
-
const file =
|
|
18153
|
+
const file = path8.join(dir, ".gitignore");
|
|
18429
18154
|
let existing;
|
|
18430
18155
|
try {
|
|
18431
18156
|
existing = await readFile5(file, "utf8");
|
|
@@ -18486,8 +18211,8 @@ async function loadTranscriptBestEffort(ref) {
|
|
|
18486
18211
|
async function stageCaptions(outDir, transcript) {
|
|
18487
18212
|
const text = transcript?.trim();
|
|
18488
18213
|
if (!text || text === "[]") return {};
|
|
18489
|
-
const compositionPath =
|
|
18490
|
-
await
|
|
18214
|
+
const compositionPath = path9.join(outDir, "tiktok-captions-composition");
|
|
18215
|
+
await cp(SHIPPED_CAPTIONS_DIR, compositionPath, { recursive: true });
|
|
18491
18216
|
return { compositionPath };
|
|
18492
18217
|
}
|
|
18493
18218
|
function patchCompositionMeta(metaJson, dims) {
|
|
@@ -18504,10 +18229,10 @@ function patchCompositionHtml(html, dims) {
|
|
|
18504
18229
|
return html.replace(/(<meta\s+name="viewport"\s+content="width=)\d+(,\s*height=)\d+(")/i, `$1${dims.w}$2${dims.h}$3`).replace(/(width:\s*)\d+(px;\s*height:\s*)\d+(px;)/i, `$1${dims.w}$2${dims.h}$3`).replace(/(data-width=")\d+(")/i, `$1${dims.w}$2`).replace(/(data-height=")\d+(")/i, `$1${dims.h}$2`);
|
|
18505
18230
|
}
|
|
18506
18231
|
async function stampCompositionDims(compositionDir, dims) {
|
|
18507
|
-
const metaPath =
|
|
18232
|
+
const metaPath = path9.join(compositionDir, "meta.json");
|
|
18508
18233
|
const rawMeta = await readFile6(metaPath, "utf8");
|
|
18509
18234
|
await writeFile2(metaPath, patchCompositionMeta(rawMeta, dims), "utf8");
|
|
18510
|
-
const htmlPath =
|
|
18235
|
+
const htmlPath = path9.join(compositionDir, "index.html");
|
|
18511
18236
|
const rawHtml = await readFile6(htmlPath, "utf8");
|
|
18512
18237
|
await writeFile2(htmlPath, patchCompositionHtml(rawHtml, dims), "utf8");
|
|
18513
18238
|
}
|
|
@@ -18647,10 +18372,6 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18647
18372
|
args: {
|
|
18648
18373
|
file: { type: "positional", required: true, description: "Path to the reference video" },
|
|
18649
18374
|
out: { type: "string", description: "Output canvas path (default <video-dir>/<name>.video.canvas.json)" },
|
|
18650
|
-
slug: {
|
|
18651
|
-
type: "string",
|
|
18652
|
-
description: "Creative slug \u2014 writes the canvas to src/creatives/<slug>/<slug>.canvas.json (repo convention)"
|
|
18653
|
-
},
|
|
18654
18375
|
frames: { type: "string", description: '"generate" (default, anchored regen) or "reuse" (wire real frames in)' },
|
|
18655
18376
|
ambient: {
|
|
18656
18377
|
type: "boolean",
|
|
@@ -18677,19 +18398,11 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18677
18398
|
}
|
|
18678
18399
|
},
|
|
18679
18400
|
async run({ args }) {
|
|
18680
|
-
const videoPath =
|
|
18681
|
-
const base =
|
|
18682
|
-
const
|
|
18683
|
-
|
|
18684
|
-
|
|
18685
|
-
`${JSON.stringify({ ok: false, error: { code: "invalid_slug", message: "--slug must be lowercase kebab (a-z, 0-9, hyphens), max 100 chars" } }, null, 2)}
|
|
18686
|
-
`
|
|
18687
|
-
);
|
|
18688
|
-
process.exit(2);
|
|
18689
|
-
}
|
|
18690
|
-
const outPath = args.out ? path11.resolve(String(args.out)) : slug ? path11.join(process.cwd(), "src", "creatives", slug, `${slug}.canvas.json`) : path11.join(path11.dirname(videoPath), `${base}.video.canvas.json`);
|
|
18691
|
-
const outDir = path11.dirname(outPath);
|
|
18692
|
-
const blueprintPath = path11.join(outDir, "prompt.json");
|
|
18401
|
+
const videoPath = path9.resolve(String(args.file));
|
|
18402
|
+
const base = path9.basename(videoPath, path9.extname(videoPath));
|
|
18403
|
+
const outPath = args.out ? path9.resolve(String(args.out)) : path9.join(path9.dirname(videoPath), `${base}.video.canvas.json`);
|
|
18404
|
+
const outDir = path9.dirname(outPath);
|
|
18405
|
+
const blueprintPath = path9.join(outDir, "prompt.json");
|
|
18693
18406
|
const frames = args.frames === "reuse" ? "reuse" : "generate";
|
|
18694
18407
|
const maxScenes = args["max-scenes"] ? Number(args["max-scenes"]) : void 0;
|
|
18695
18408
|
if (Number.isFinite(maxScenes)) {
|
|
@@ -18708,7 +18421,7 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18708
18421
|
shotCuts
|
|
18709
18422
|
});
|
|
18710
18423
|
const { blueprint, elements, transcript, creditsSpent } = await runAnalysisPasses(deconstructCanvas, selectModel);
|
|
18711
|
-
await
|
|
18424
|
+
await mkdir(outDir, { recursive: true });
|
|
18712
18425
|
const annotated = annotateBlueprintWithElements(blueprint, elements);
|
|
18713
18426
|
await writeFile2(blueprintPath, `${JSON.stringify(annotated, null, 2)}
|
|
18714
18427
|
`, "utf8");
|
|
@@ -18729,10 +18442,10 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18729
18442
|
`
|
|
18730
18443
|
);
|
|
18731
18444
|
}
|
|
18732
|
-
const compositionDest =
|
|
18733
|
-
await
|
|
18445
|
+
const compositionDest = path9.join(outDir, "video-overlay-composition");
|
|
18446
|
+
await cp(SHIPPED_COMPOSITION_DIR, compositionDest, { recursive: true });
|
|
18734
18447
|
await stampCompositionDims(compositionDest, outDims);
|
|
18735
|
-
const indexPath =
|
|
18448
|
+
const indexPath = path9.join(compositionDest, "index.html");
|
|
18736
18449
|
const overlayHtml = buildOverlayHtml(blueprint, { captionsActive: Boolean(transcript) });
|
|
18737
18450
|
const indexHtml = await readFile6(indexPath, "utf8");
|
|
18738
18451
|
const injected = indexHtml.replace("<!--OVERLAYS-->", () => overlayHtml);
|
|
@@ -18748,9 +18461,9 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18748
18461
|
const opts = {
|
|
18749
18462
|
imageModel,
|
|
18750
18463
|
videoModel,
|
|
18751
|
-
overlayCompositionPath:
|
|
18752
|
-
captionsCompositionPath: captions.compositionPath ?
|
|
18753
|
-
blueprintPath:
|
|
18464
|
+
overlayCompositionPath: path9.relative(outDir, compositionDest),
|
|
18465
|
+
captionsCompositionPath: captions.compositionPath ? path9.relative(outDir, captions.compositionPath) : void 0,
|
|
18466
|
+
blueprintPath: path9.relative(outDir, blueprintPath),
|
|
18754
18467
|
frames,
|
|
18755
18468
|
ambient: Boolean(args.ambient),
|
|
18756
18469
|
...args.aspect ? { aspect: String(args.aspect) } : {},
|
|
@@ -18808,7 +18521,7 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18808
18521
|
run_estimated_credits: validation.estimatedCredits
|
|
18809
18522
|
},
|
|
18810
18523
|
checklist: {
|
|
18811
|
-
edit_prompt: `Edit ${
|
|
18524
|
+
edit_prompt: `Edit ${path9.basename(blueprintPath)} \u2014 the blueprint deconstructed from your video; rewrite it into the ad you want (cast, palette, copy, claims). Every scene frame reads it via target_blueprint.`,
|
|
18812
18525
|
recurring_elements_to_supply: report.elements,
|
|
18813
18526
|
voices_to_confirm: report.dialogue.map((d) => ({
|
|
18814
18527
|
scene: d.scene,
|
|
@@ -18835,7 +18548,7 @@ var scaffoldVideoCommand = defineCommand90({
|
|
|
18835
18548
|
|
|
18836
18549
|
// src/commands/canvas/set-prompt.ts
|
|
18837
18550
|
import { readFile as readFile7, writeFile as writeFile3 } from "fs/promises";
|
|
18838
|
-
import
|
|
18551
|
+
import path10 from "path";
|
|
18839
18552
|
import { defineCommand as defineCommand91 } from "citty";
|
|
18840
18553
|
function setNodePrompt(canvas, nodeId, text) {
|
|
18841
18554
|
const nodes = canvas?.nodes;
|
|
@@ -18863,7 +18576,7 @@ var setPromptCommand = defineCommand91({
|
|
|
18863
18576
|
"text-file": { type: "string", description: "Read the new prompt from a UTF-8 file (preserves accents/newlines)" }
|
|
18864
18577
|
},
|
|
18865
18578
|
async run({ args }) {
|
|
18866
|
-
const filePath =
|
|
18579
|
+
const filePath = path10.resolve(String(args.file));
|
|
18867
18580
|
let canvas;
|
|
18868
18581
|
try {
|
|
18869
18582
|
canvas = JSON.parse(await readFile7(filePath, "utf8"));
|
|
@@ -18873,7 +18586,7 @@ var setPromptCommand = defineCommand91({
|
|
|
18873
18586
|
process.exit(2);
|
|
18874
18587
|
}
|
|
18875
18588
|
let text;
|
|
18876
|
-
if (args["text-file"]) text = await readFile7(
|
|
18589
|
+
if (args["text-file"]) text = await readFile7(path10.resolve(String(args["text-file"])), "utf8");
|
|
18877
18590
|
else if (args.text !== void 0) text = String(args.text);
|
|
18878
18591
|
else {
|
|
18879
18592
|
process.stderr.write(
|
|
@@ -18894,7 +18607,7 @@ var setPromptCommand = defineCommand91({
|
|
|
18894
18607
|
process.exit(2);
|
|
18895
18608
|
return;
|
|
18896
18609
|
}
|
|
18897
|
-
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated,
|
|
18610
|
+
const validation = await validateCanvasDeep(resolveRelativeCanvasPaths(updated, path10.dirname(filePath)), defaultRegistry());
|
|
18898
18611
|
if (!validation.ok) {
|
|
18899
18612
|
process.stderr.write(`${JSON.stringify({ ok: false, error: { code: "validation", issues: validation.issues } }, null, 2)}
|
|
18900
18613
|
`);
|
|
@@ -18910,7 +18623,7 @@ var setPromptCommand = defineCommand91({
|
|
|
18910
18623
|
|
|
18911
18624
|
// src/commands/canvas/validate.ts
|
|
18912
18625
|
import { readFile as readFile8 } from "fs/promises";
|
|
18913
|
-
import
|
|
18626
|
+
import path11 from "path";
|
|
18914
18627
|
import { defineCommand as defineCommand92 } from "citty";
|
|
18915
18628
|
var validateCommand = defineCommand92({
|
|
18916
18629
|
meta: {
|
|
@@ -18919,7 +18632,7 @@ var validateCommand = defineCommand92({
|
|
|
18919
18632
|
},
|
|
18920
18633
|
args: { file: { type: "positional", required: true, description: "Path to canvas JSON" } },
|
|
18921
18634
|
async run({ args }) {
|
|
18922
|
-
const filePath =
|
|
18635
|
+
const filePath = path11.resolve(String(args.file));
|
|
18923
18636
|
const raw = await readFile8(filePath, "utf8");
|
|
18924
18637
|
let parsed;
|
|
18925
18638
|
try {
|
|
@@ -18930,7 +18643,7 @@ var validateCommand = defineCommand92({
|
|
|
18930
18643
|
`);
|
|
18931
18644
|
process.exit(2);
|
|
18932
18645
|
}
|
|
18933
|
-
parsed = resolveRelativeCanvasPaths(parsed,
|
|
18646
|
+
parsed = resolveRelativeCanvasPaths(parsed, path11.dirname(filePath));
|
|
18934
18647
|
const result = await validateCanvasDeep(parsed, defaultRegistry());
|
|
18935
18648
|
if (!result.ok) {
|
|
18936
18649
|
process.stderr.write(`${JSON.stringify({ ok: false, issues: result.issues }, null, 2)}
|
|
@@ -19067,16 +18780,6 @@ registerSchema({
|
|
|
19067
18780
|
type: "string",
|
|
19068
18781
|
description: "Optional URL of the original reference ad",
|
|
19069
18782
|
required: false
|
|
19070
|
-
},
|
|
19071
|
-
slug: {
|
|
19072
|
-
type: "string",
|
|
19073
|
-
description: "Creative slug (src/creatives/<slug>/) \u2014 attaches the image to that creative's row",
|
|
19074
|
-
required: false
|
|
19075
|
-
},
|
|
19076
|
-
runId: {
|
|
19077
|
-
type: "string",
|
|
19078
|
-
description: "Canvas run id (r_\u2026) of the approved generation to pin as published",
|
|
19079
|
-
required: false
|
|
19080
18783
|
}
|
|
19081
18784
|
}
|
|
19082
18785
|
});
|
|
@@ -19086,13 +18789,6 @@ function detectCreativeContentType(filePath) {
|
|
|
19086
18789
|
unsupportedMessage: "Unsupported creative image extension. Use PNG, JPG, or WebP."
|
|
19087
18790
|
});
|
|
19088
18791
|
}
|
|
19089
|
-
function chatIdFromEnv() {
|
|
19090
|
-
try {
|
|
19091
|
-
return getEnv().BAKER_CHAT_ID || void 0;
|
|
19092
|
-
} catch {
|
|
19093
|
-
return void 0;
|
|
19094
|
-
}
|
|
19095
|
-
}
|
|
19096
18792
|
function parseOptionalUrl(value) {
|
|
19097
18793
|
if (value === void 0 || value.trim() === "") {
|
|
19098
18794
|
return void 0;
|
|
@@ -19123,11 +18819,7 @@ async function publishCreative(args, deps = defaultImageApiDeps) {
|
|
|
19123
18819
|
return publishImageAsCreative(deps, {
|
|
19124
18820
|
imageId: upload.imageId,
|
|
19125
18821
|
title,
|
|
19126
|
-
sourceReferenceUrl
|
|
19127
|
-
slug: args.slug,
|
|
19128
|
-
runId: args.runId,
|
|
19129
|
-
// Attribute the publish to the driving chat (injected by the bridge).
|
|
19130
|
-
chatId: chatIdFromEnv()
|
|
18822
|
+
sourceReferenceUrl
|
|
19131
18823
|
});
|
|
19132
18824
|
}
|
|
19133
18825
|
var publishCommand = defineCommand94({
|
|
@@ -19143,16 +18835,6 @@ var publishCommand = defineCommand94({
|
|
|
19143
18835
|
type: "string",
|
|
19144
18836
|
description: "Optional URL of the original reference ad",
|
|
19145
18837
|
required: false
|
|
19146
|
-
},
|
|
19147
|
-
slug: {
|
|
19148
|
-
type: "string",
|
|
19149
|
-
description: "Creative slug (src/creatives/<slug>/) \u2014 attaches the image to that creative's row",
|
|
19150
|
-
required: false
|
|
19151
|
-
},
|
|
19152
|
-
runId: {
|
|
19153
|
-
type: "string",
|
|
19154
|
-
description: "Canvas run id (r_\u2026) of the approved generation to pin as published",
|
|
19155
|
-
required: false
|
|
19156
18838
|
}
|
|
19157
18839
|
},
|
|
19158
18840
|
run: async ({ args }) => {
|
|
@@ -19171,9 +18853,7 @@ var publishCommand = defineCommand94({
|
|
|
19171
18853
|
file,
|
|
19172
18854
|
title,
|
|
19173
18855
|
context: args.context,
|
|
19174
|
-
sourceReferenceUrl: args.sourceReferenceUrl
|
|
19175
|
-
slug: args.slug,
|
|
19176
|
-
runId: args.runId
|
|
18856
|
+
sourceReferenceUrl: args.sourceReferenceUrl
|
|
19177
18857
|
});
|
|
19178
18858
|
writeJson({ ok: true, data });
|
|
19179
18859
|
} catch (err) {
|
|
@@ -20071,9 +19751,9 @@ async function readImageBuffer(pathOrUrl) {
|
|
|
20071
19751
|
}
|
|
20072
19752
|
return readFile10(pathOrUrl);
|
|
20073
19753
|
}
|
|
20074
|
-
async function isDirectory(
|
|
19754
|
+
async function isDirectory(path12) {
|
|
20075
19755
|
try {
|
|
20076
|
-
const s = await stat2(
|
|
19756
|
+
const s = await stat2(path12);
|
|
20077
19757
|
return s.isDirectory();
|
|
20078
19758
|
} catch {
|
|
20079
19759
|
return false;
|