@koda-sl/baker-cli 0.99.1-dev.5b1957cc → 0.100.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 +2 -2
- package/dist/{chunk-26K7V346.js → chunk-3JVYU72O.js} +4 -4
- package/dist/chunk-3JVYU72O.js.map +1 -0
- package/dist/cli.js +224 -254
- package/dist/cli.js.map +1 -1
- package/dist/engine/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-26K7V346.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
defaultRegistry,
|
|
10
10
|
generateCatalog,
|
|
11
11
|
validateCanvasDeep
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-3JVYU72O.js";
|
|
13
13
|
|
|
14
14
|
// src/cli.ts
|
|
15
15
|
import { defineCommand as defineCommand152, runMain } from "citty";
|
|
@@ -516,14 +516,140 @@ ${description}`;
|
|
|
516
516
|
return SCHEDULE_SIGNALS.some((re) => re.test(haystack));
|
|
517
517
|
}
|
|
518
518
|
|
|
519
|
+
// src/commands/actions/skillCatalog.ts
|
|
520
|
+
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
521
|
+
import { dirname, join } from "path";
|
|
522
|
+
var DESCRIPTION_MAX = 600;
|
|
523
|
+
var SKILLS_SUBPATH = join(".claude", "skills");
|
|
524
|
+
var EXCLUDED_SKILLS = /* @__PURE__ */ new Set(["actions"]);
|
|
525
|
+
function stripQuotes(value) {
|
|
526
|
+
const trimmed = value.trim();
|
|
527
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
528
|
+
return trimmed.slice(1, -1).replace(/\\"/g, '"').replace(/\\n/g, "\n");
|
|
529
|
+
}
|
|
530
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
531
|
+
return trimmed.slice(1, -1).replace(/''/g, "'");
|
|
532
|
+
}
|
|
533
|
+
return trimmed;
|
|
534
|
+
}
|
|
535
|
+
function extractFrontmatterLines(md) {
|
|
536
|
+
if (!md.startsWith("---")) return null;
|
|
537
|
+
const end = md.indexOf("\n---", 3);
|
|
538
|
+
if (end === -1) return null;
|
|
539
|
+
return md.slice(md.indexOf("\n", 3) + 1, end).split("\n");
|
|
540
|
+
}
|
|
541
|
+
var BLOCK_SCALAR = /^([|>])[+-]?$/;
|
|
542
|
+
function collectBlockLines(lines, start) {
|
|
543
|
+
const collected = [];
|
|
544
|
+
for (let i = start; i < lines.length; i++) {
|
|
545
|
+
const line = lines[i] ?? "";
|
|
546
|
+
if (line.trim() === "") {
|
|
547
|
+
collected.push("");
|
|
548
|
+
} else if (/^\s/.test(line)) {
|
|
549
|
+
collected.push(line.trim());
|
|
550
|
+
} else {
|
|
551
|
+
break;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
while (collected.length > 0 && collected.at(-1) === "") collected.pop();
|
|
555
|
+
return collected;
|
|
556
|
+
}
|
|
557
|
+
function foldLines(collected) {
|
|
558
|
+
const paragraphs = [];
|
|
559
|
+
let buffer = [];
|
|
560
|
+
for (const line of collected) {
|
|
561
|
+
if (line === "") {
|
|
562
|
+
if (buffer.length > 0) paragraphs.push(buffer.join(" "));
|
|
563
|
+
buffer = [];
|
|
564
|
+
} else {
|
|
565
|
+
buffer.push(line);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
if (buffer.length > 0) paragraphs.push(buffer.join(" "));
|
|
569
|
+
return paragraphs.join("\n");
|
|
570
|
+
}
|
|
571
|
+
function readBlockScalar(lines, start, style) {
|
|
572
|
+
const collected = collectBlockLines(lines, start);
|
|
573
|
+
return style === "|" ? collected.join("\n") : foldLines(collected);
|
|
574
|
+
}
|
|
575
|
+
function readField(lines, field) {
|
|
576
|
+
for (let i = 0; i < lines.length; i++) {
|
|
577
|
+
const match = (lines[i] ?? "").match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
|
|
578
|
+
if (!match || match[1] !== field) continue;
|
|
579
|
+
const inline = (match[2] ?? "").trim();
|
|
580
|
+
const scalar = inline.match(BLOCK_SCALAR);
|
|
581
|
+
if (scalar) {
|
|
582
|
+
return readBlockScalar(lines, i + 1, scalar[1]);
|
|
583
|
+
}
|
|
584
|
+
return stripQuotes(inline);
|
|
585
|
+
}
|
|
586
|
+
return null;
|
|
587
|
+
}
|
|
588
|
+
function parseSkillFrontmatter(md) {
|
|
589
|
+
const lines = extractFrontmatterLines(md);
|
|
590
|
+
if (!lines) return null;
|
|
591
|
+
const name = readField(lines, "name");
|
|
592
|
+
const description = readField(lines, "description");
|
|
593
|
+
if (!name || !description) return null;
|
|
594
|
+
const trimmed = description.length > DESCRIPTION_MAX ? `${description.slice(0, DESCRIPTION_MAX)}\u2026` : description;
|
|
595
|
+
return { name, description: trimmed };
|
|
596
|
+
}
|
|
597
|
+
function findSkillsDir(startDir) {
|
|
598
|
+
let dir = startDir;
|
|
599
|
+
for (; ; ) {
|
|
600
|
+
const candidate = join(dir, SKILLS_SUBPATH);
|
|
601
|
+
if (existsSync(candidate)) return candidate;
|
|
602
|
+
const parent = dirname(dir);
|
|
603
|
+
if (parent === dir) return null;
|
|
604
|
+
dir = parent;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
function readSkillCatalog(startDir) {
|
|
608
|
+
const skillsDir = findSkillsDir(startDir);
|
|
609
|
+
if (!skillsDir) return [];
|
|
610
|
+
const entries = [];
|
|
611
|
+
for (const dirent of readdirSync(skillsDir, { withFileTypes: true })) {
|
|
612
|
+
if (!dirent.isDirectory() || EXCLUDED_SKILLS.has(dirent.name)) continue;
|
|
613
|
+
const skillFile = join(skillsDir, dirent.name, "SKILL.md");
|
|
614
|
+
if (!existsSync(skillFile)) continue;
|
|
615
|
+
try {
|
|
616
|
+
const parsed = parseSkillFrontmatter(readFileSync(skillFile, "utf8"));
|
|
617
|
+
if (parsed) entries.push(parsed);
|
|
618
|
+
} catch {
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
622
|
+
}
|
|
623
|
+
|
|
519
624
|
// src/commands/actions/claim.ts
|
|
520
625
|
registerSchema({
|
|
521
626
|
command: "actions.claim",
|
|
522
|
-
description: "Claim an action for the current chat (live \u2014 visible to other chats immediately). Returns action details
|
|
627
|
+
description: "Claim an action for the current chat (live \u2014 visible to other chats immediately). Returns action details plus a fast-model recommendation of which skills to load for the work (`recommendedSkills`).",
|
|
523
628
|
args: {
|
|
524
629
|
id: { type: "string", description: "Action ID", required: true }
|
|
525
630
|
}
|
|
526
631
|
});
|
|
632
|
+
async function recommendSkills(actionId) {
|
|
633
|
+
const skills = readSkillCatalog(process.cwd());
|
|
634
|
+
if (skills.length === 0) return [];
|
|
635
|
+
const response = await apiPost(
|
|
636
|
+
"/api/actions/recommend-skills",
|
|
637
|
+
{ actionId, skills }
|
|
638
|
+
);
|
|
639
|
+
return response.data?.recommendations ?? [];
|
|
640
|
+
}
|
|
641
|
+
function buildHints(recommendations) {
|
|
642
|
+
if (recommendations.length === 0) {
|
|
643
|
+
return [
|
|
644
|
+
"Review the action name, description, and tags above \u2014 then load any skills that would help you complete this work."
|
|
645
|
+
];
|
|
646
|
+
}
|
|
647
|
+
return [
|
|
648
|
+
"Recommended skills for this action (load the ones you'll use):",
|
|
649
|
+
...recommendations.map((r) => ` /${r.name} \u2014 ${r.reason}`),
|
|
650
|
+
"Suggestions from the action's name/description/tags \u2014 load others if the work needs them."
|
|
651
|
+
];
|
|
652
|
+
}
|
|
527
653
|
var claimCommand = defineCommand({
|
|
528
654
|
meta: {
|
|
529
655
|
name: "claim",
|
|
@@ -545,10 +671,13 @@ var claimCommand = defineCommand({
|
|
|
545
671
|
actionId: id,
|
|
546
672
|
chatId
|
|
547
673
|
});
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
674
|
+
let recommendedSkills = [];
|
|
675
|
+
try {
|
|
676
|
+
recommendedSkills = await recommendSkills(id);
|
|
677
|
+
} catch {
|
|
678
|
+
}
|
|
679
|
+
const data = response.data ? { ...response.data, recommendedSkills } : response.data;
|
|
680
|
+
writeJson({ ok: response.ok, data, hints: buildHints(recommendedSkills) });
|
|
552
681
|
} catch (err) {
|
|
553
682
|
failApi(err);
|
|
554
683
|
}
|
|
@@ -1396,12 +1525,12 @@ import { defineCommand as defineCommand19 } from "citty";
|
|
|
1396
1525
|
|
|
1397
1526
|
// src/commands/ads/cache.ts
|
|
1398
1527
|
import { createHash } from "crypto";
|
|
1399
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
1528
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, rmSync, writeFileSync } from "fs";
|
|
1400
1529
|
import { homedir } from "os";
|
|
1401
|
-
import { join } from "path";
|
|
1402
|
-
var CACHE_DIR =
|
|
1530
|
+
import { join as join2 } from "path";
|
|
1531
|
+
var CACHE_DIR = join2(homedir(), ".baker", "cache", "ads");
|
|
1403
1532
|
function ensureDir(dir) {
|
|
1404
|
-
if (!
|
|
1533
|
+
if (!existsSync2(dir)) {
|
|
1405
1534
|
mkdirSync(dir, { recursive: true });
|
|
1406
1535
|
}
|
|
1407
1536
|
}
|
|
@@ -1409,17 +1538,17 @@ function hashKey(key) {
|
|
|
1409
1538
|
return createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
1410
1539
|
}
|
|
1411
1540
|
function cachePath(category, key) {
|
|
1412
|
-
const dir =
|
|
1541
|
+
const dir = join2(CACHE_DIR, category);
|
|
1413
1542
|
ensureDir(dir);
|
|
1414
|
-
return
|
|
1543
|
+
return join2(dir, `${hashKey(key)}.json`);
|
|
1415
1544
|
}
|
|
1416
1545
|
function cacheGet(category, key) {
|
|
1417
1546
|
const path11 = cachePath(category, key);
|
|
1418
|
-
if (!
|
|
1547
|
+
if (!existsSync2(path11)) {
|
|
1419
1548
|
return null;
|
|
1420
1549
|
}
|
|
1421
1550
|
try {
|
|
1422
|
-
const raw =
|
|
1551
|
+
const raw = readFileSync2(path11, "utf-8");
|
|
1423
1552
|
const entry = JSON.parse(raw);
|
|
1424
1553
|
if (entry.expiresAt < Date.now()) {
|
|
1425
1554
|
rmSync(path11, { force: true });
|
|
@@ -3166,7 +3295,7 @@ var library = defineCommand27({
|
|
|
3166
3295
|
});
|
|
3167
3296
|
|
|
3168
3297
|
// src/commands/ads/google/query.ts
|
|
3169
|
-
import { appendFileSync, existsSync as
|
|
3298
|
+
import { appendFileSync, existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
3170
3299
|
import { resolve } from "path";
|
|
3171
3300
|
import { defineCommand as defineCommand28 } from "citty";
|
|
3172
3301
|
|
|
@@ -3443,7 +3572,7 @@ function extractFields(rows) {
|
|
|
3443
3572
|
function writeRowsToFile(filePath, rows, fields, append) {
|
|
3444
3573
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
3445
3574
|
if (ext === "csv") {
|
|
3446
|
-
if (!append || !
|
|
3575
|
+
if (!append || !existsSync3(filePath)) {
|
|
3447
3576
|
writeFileSync2(filePath, `${toCsvRow(fields)}
|
|
3448
3577
|
`, "utf-8");
|
|
3449
3578
|
}
|
|
@@ -3452,15 +3581,15 @@ function writeRowsToFile(filePath, rows, fields, append) {
|
|
|
3452
3581
|
`, "utf-8");
|
|
3453
3582
|
} else if (ext === "jsonl") {
|
|
3454
3583
|
const lines = rows.map((row) => JSON.stringify(row));
|
|
3455
|
-
if (append &&
|
|
3584
|
+
if (append && existsSync3(filePath)) {
|
|
3456
3585
|
appendFileSync(filePath, `${lines.join("\n")}
|
|
3457
3586
|
`, "utf-8");
|
|
3458
3587
|
} else {
|
|
3459
3588
|
writeFileSync2(filePath, `${lines.join("\n")}
|
|
3460
3589
|
`, "utf-8");
|
|
3461
3590
|
}
|
|
3462
|
-
} else if (append &&
|
|
3463
|
-
const existing = JSON.parse(
|
|
3591
|
+
} else if (append && existsSync3(filePath)) {
|
|
3592
|
+
const existing = JSON.parse(readFileSync3(filePath, "utf-8"));
|
|
3464
3593
|
writeFileSync2(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
3465
3594
|
} else {
|
|
3466
3595
|
writeFileSync2(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -4596,7 +4725,7 @@ Examples \u2014 common AI questions:
|
|
|
4596
4725
|
});
|
|
4597
4726
|
|
|
4598
4727
|
// src/commands/ads/linkedin/audience-size.ts
|
|
4599
|
-
import { readFileSync as
|
|
4728
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
4600
4729
|
import { defineCommand as defineCommand33 } from "citty";
|
|
4601
4730
|
function loadTargeting(args) {
|
|
4602
4731
|
const inline = args.targeting;
|
|
@@ -4610,7 +4739,7 @@ function loadTargeting(args) {
|
|
|
4610
4739
|
const file = args["targeting-file"];
|
|
4611
4740
|
if (file) {
|
|
4612
4741
|
try {
|
|
4613
|
-
return JSON.parse(
|
|
4742
|
+
return JSON.parse(readFileSync4(file, "utf-8"));
|
|
4614
4743
|
} catch (e) {
|
|
4615
4744
|
handleLinkedinError(
|
|
4616
4745
|
new Error(`Failed to read --targeting-file: ${e instanceof Error ? e.message : "I/O error"}`)
|
|
@@ -4789,7 +4918,7 @@ Examples:
|
|
|
4789
4918
|
});
|
|
4790
4919
|
|
|
4791
4920
|
// src/commands/ads/linkedin/bid-pricing.ts
|
|
4792
|
-
import { readFileSync as
|
|
4921
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
4793
4922
|
import { defineCommand as defineCommand35 } from "citty";
|
|
4794
4923
|
function loadTargeting2(args) {
|
|
4795
4924
|
const inline = args.targeting;
|
|
@@ -4803,7 +4932,7 @@ function loadTargeting2(args) {
|
|
|
4803
4932
|
const file = args["targeting-file"];
|
|
4804
4933
|
if (file) {
|
|
4805
4934
|
try {
|
|
4806
|
-
return JSON.parse(
|
|
4935
|
+
return JSON.parse(readFileSync5(file, "utf-8"));
|
|
4807
4936
|
} catch (e) {
|
|
4808
4937
|
handleLinkedinError(
|
|
4809
4938
|
new Error(`Failed to read --targeting-file: ${e instanceof Error ? e.message : "I/O error"}`)
|
|
@@ -5367,7 +5496,7 @@ Subcommands:
|
|
|
5367
5496
|
});
|
|
5368
5497
|
|
|
5369
5498
|
// src/commands/ads/linkedin/forecast.ts
|
|
5370
|
-
import { readFileSync as
|
|
5499
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
5371
5500
|
import { defineCommand as defineCommand43 } from "citty";
|
|
5372
5501
|
function loadTargeting3(args) {
|
|
5373
5502
|
const inline = args.targeting;
|
|
@@ -5381,7 +5510,7 @@ function loadTargeting3(args) {
|
|
|
5381
5510
|
const file = args["targeting-file"];
|
|
5382
5511
|
if (file) {
|
|
5383
5512
|
try {
|
|
5384
|
-
return JSON.parse(
|
|
5513
|
+
return JSON.parse(readFileSync6(file, "utf-8"));
|
|
5385
5514
|
} catch (e) {
|
|
5386
5515
|
handleLinkedinError(
|
|
5387
5516
|
new Error(`Failed to read --targeting-file: ${e instanceof Error ? e.message : "I/O error"}`)
|
|
@@ -8849,7 +8978,7 @@ import { defineCommand as defineCommand83 } from "citty";
|
|
|
8849
8978
|
import { execFile as execFile2 } from "child_process";
|
|
8850
8979
|
import { mkdtemp, readdir as readdir2, readFile as readFile4, rm as rm2 } from "fs/promises";
|
|
8851
8980
|
import { tmpdir } from "os";
|
|
8852
|
-
import { join as
|
|
8981
|
+
import { join as join3 } from "path";
|
|
8853
8982
|
import { promisify as promisify2 } from "util";
|
|
8854
8983
|
var execFileAsync2 = promisify2(execFile2);
|
|
8855
8984
|
var PYSCENEDETECT_THRESHOLD = 18;
|
|
@@ -8892,7 +9021,7 @@ function parsePySceneDetectCsvCuts(csv) {
|
|
|
8892
9021
|
return [...new Set(cuts)].sort((a, b) => a - b);
|
|
8893
9022
|
}
|
|
8894
9023
|
async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs) {
|
|
8895
|
-
const outDir = await mkdtemp(
|
|
9024
|
+
const outDir = await mkdtemp(join3(tmpdir(), "baker-scenedetect-"));
|
|
8896
9025
|
try {
|
|
8897
9026
|
await execFileAsync2(
|
|
8898
9027
|
"scenedetect",
|
|
@@ -8913,7 +9042,7 @@ async function runSceneDetectOnce(filePath, threshold, minSceneLenS, timeoutMs)
|
|
|
8913
9042
|
);
|
|
8914
9043
|
const csvName = (await readdir2(outDir)).find((f) => f.toLowerCase().endsWith(".csv"));
|
|
8915
9044
|
if (!csvName) return [];
|
|
8916
|
-
return parsePySceneDetectCsvCuts(await readFile4(
|
|
9045
|
+
return parsePySceneDetectCsvCuts(await readFile4(join3(outDir, csvName), "utf-8"));
|
|
8917
9046
|
} finally {
|
|
8918
9047
|
await rm2(outDir, { recursive: true, force: true });
|
|
8919
9048
|
}
|
|
@@ -11012,15 +11141,15 @@ function xfadeSpineArgs(clips) {
|
|
|
11012
11141
|
let cur = "c0";
|
|
11013
11142
|
let accLen = clipInputLen(clips[0]);
|
|
11014
11143
|
for (let k = 0; k < n - 1; k++) {
|
|
11015
|
-
const
|
|
11144
|
+
const join5 = clips[k].out;
|
|
11016
11145
|
const next = `c${k + 1}`;
|
|
11017
11146
|
const out = k === n - 2 ? "v" : `j${k + 1}`;
|
|
11018
|
-
if (
|
|
11019
|
-
const offset = Math.max(0, accLen -
|
|
11147
|
+
if (join5) {
|
|
11148
|
+
const offset = Math.max(0, accLen - join5.dur);
|
|
11020
11149
|
filt.push(
|
|
11021
|
-
`[${cur}][${next}]xfade=transition=${
|
|
11150
|
+
`[${cur}][${next}]xfade=transition=${join5.xfade}:duration=${join5.dur.toFixed(3)}:offset=${offset.toFixed(3)}[${out}]`
|
|
11022
11151
|
);
|
|
11023
|
-
accLen = accLen -
|
|
11152
|
+
accLen = accLen - join5.dur + clipInputLen(clips[k + 1]);
|
|
11024
11153
|
} else {
|
|
11025
11154
|
filt.push(`[${cur}][${next}]concat=n=2:v=1[${out}]`);
|
|
11026
11155
|
accLen += clipInputLen(clips[k + 1]);
|
|
@@ -11457,9 +11586,9 @@ function videoReport(input, elementsInput) {
|
|
|
11457
11586
|
}
|
|
11458
11587
|
|
|
11459
11588
|
// src/commands/canvas/composition-path.ts
|
|
11460
|
-
import { existsSync as
|
|
11589
|
+
import { existsSync as existsSync4 } from "fs";
|
|
11461
11590
|
import path6 from "path";
|
|
11462
|
-
function resolveShippedCanvasDir(name, startDir, exists =
|
|
11591
|
+
function resolveShippedCanvasDir(name, startDir, exists = existsSync4, maxDepth = 8) {
|
|
11463
11592
|
const rel = path6.join("canvas", name);
|
|
11464
11593
|
let dir = startDir;
|
|
11465
11594
|
for (let i = 0; i < maxDepth; i++) {
|
|
@@ -11969,7 +12098,6 @@ Subcommands:
|
|
|
11969
12098
|
import { defineCommand as defineCommand88 } from "citty";
|
|
11970
12099
|
|
|
11971
12100
|
// src/commands/creatives/publish.ts
|
|
11972
|
-
import { extname as extname2 } from "path";
|
|
11973
12101
|
import { defineCommand as defineCommand87 } from "citty";
|
|
11974
12102
|
|
|
11975
12103
|
// src/commands/images/api.ts
|
|
@@ -12016,6 +12144,9 @@ async function uploadLocalImage(args, deps = defaultImageApiDeps) {
|
|
|
12016
12144
|
function getImage(deps, imageId) {
|
|
12017
12145
|
return deps.get("/api/images/get", { id: imageId });
|
|
12018
12146
|
}
|
|
12147
|
+
function updateImageTags(deps, args) {
|
|
12148
|
+
return deps.post("/api/images/tag", args);
|
|
12149
|
+
}
|
|
12019
12150
|
async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
12020
12151
|
const timeoutMs = opts.timeoutMs ?? imageProcessingTimeoutMs;
|
|
12021
12152
|
const pollIntervalMs = opts.pollIntervalMs ?? imageReadyPollIntervalMs;
|
|
@@ -12037,68 +12168,31 @@ async function waitForReadyImage(deps, imageId, opts = {}) {
|
|
|
12037
12168
|
|
|
12038
12169
|
// src/commands/creatives/publish.ts
|
|
12039
12170
|
var creativeTag = "creative";
|
|
12040
|
-
var
|
|
12041
|
-
var creativeTags = [creativeTag, winningAdsTag];
|
|
12042
|
-
var creativeImageContentTypes = ["image/png", "image/jpeg", "image/webp"];
|
|
12043
|
-
var creativeVideoContentTypesByExtension = {
|
|
12044
|
-
".mp4": "video/mp4",
|
|
12045
|
-
".mov": "video/quicktime",
|
|
12046
|
-
".webm": "video/webm"
|
|
12047
|
-
};
|
|
12048
|
-
var videoProcessingTimeoutMs = 5 * 60 * 1e3;
|
|
12049
|
-
var videoReadyPollIntervalMs = 5e3;
|
|
12050
|
-
var defaultCreativePublishDeps = {
|
|
12051
|
-
...defaultImageApiDeps,
|
|
12052
|
-
fetch
|
|
12053
|
-
};
|
|
12171
|
+
var creativeContentTypes = ["image/png", "image/jpeg", "image/webp"];
|
|
12054
12172
|
registerSchema({
|
|
12055
12173
|
command: "creatives.publish",
|
|
12056
|
-
description: "Publish a final creative image
|
|
12174
|
+
description: "Publish a final static creative image to Baker Images, apply the official creative tag, and return an image reference.",
|
|
12057
12175
|
args: {
|
|
12058
|
-
file: { type: "string", description: "Local PNG/JPG/WebP
|
|
12176
|
+
file: { type: "string", description: "Local PNG/JPG/WebP creative image path", required: true },
|
|
12059
12177
|
title: { type: "string", description: "Human title for the creative output", required: true },
|
|
12060
|
-
|
|
12178
|
+
context: { type: "string", description: "Optional describe context for the image row", required: false }
|
|
12061
12179
|
}
|
|
12062
12180
|
});
|
|
12063
|
-
function uniqueTags(tags) {
|
|
12064
|
-
return [...new Set(tags.map((tag) => tag.trim()).filter(Boolean))];
|
|
12065
|
-
}
|
|
12066
|
-
function requiredMetadata(args) {
|
|
12067
|
-
const title = args.title.trim();
|
|
12068
|
-
const body = args.body.trim();
|
|
12069
|
-
if (!title) {
|
|
12070
|
-
throw new ApiError("VALIDATION_ERROR", "--title is required");
|
|
12071
|
-
}
|
|
12072
|
-
if (!body) {
|
|
12073
|
-
throw new ApiError("VALIDATION_ERROR", "--body is required");
|
|
12074
|
-
}
|
|
12075
|
-
return { title, body };
|
|
12076
|
-
}
|
|
12077
12181
|
function detectCreativeContentType(filePath) {
|
|
12078
|
-
const ext = extname2(filePath).toLowerCase();
|
|
12079
|
-
const videoContentType = creativeVideoContentTypesByExtension[ext];
|
|
12080
|
-
if (videoContentType) {
|
|
12081
|
-
return videoContentType;
|
|
12082
|
-
}
|
|
12083
12182
|
return detectImageContentType(filePath, {
|
|
12084
|
-
allowedContentTypes:
|
|
12085
|
-
unsupportedMessage: "Unsupported creative extension. Use PNG, JPG,
|
|
12183
|
+
allowedContentTypes: creativeContentTypes,
|
|
12184
|
+
unsupportedMessage: "Unsupported creative image extension. Use PNG, JPG, or WebP."
|
|
12086
12185
|
});
|
|
12087
12186
|
}
|
|
12088
|
-
function isVideoContentType(contentType) {
|
|
12089
|
-
return contentType.startsWith("video/");
|
|
12090
|
-
}
|
|
12091
12187
|
function imageToCreativeReference(image, title) {
|
|
12092
12188
|
if (!image.imageUrl) {
|
|
12093
12189
|
throw new ApiError("IMAGE_PROCESSING_ERROR", "Published image is missing imageUrl");
|
|
12094
12190
|
}
|
|
12095
|
-
const tags = uniqueTags([...image.tags ?? [], ...creativeTags]);
|
|
12096
12191
|
return {
|
|
12097
12192
|
type: "image",
|
|
12098
12193
|
slug: image._id,
|
|
12099
12194
|
title,
|
|
12100
|
-
|
|
12101
|
-
tags,
|
|
12195
|
+
tags: image.tags?.includes(creativeTag) ? image.tags : [...image.tags ?? [], creativeTag],
|
|
12102
12196
|
imageUrl: image.imageUrl,
|
|
12103
12197
|
thumbnailUrl: image.thumbnailUrl ?? image.imageUrl,
|
|
12104
12198
|
storageKey: image.storageKey,
|
|
@@ -12108,150 +12202,53 @@ function imageToCreativeReference(image, title) {
|
|
|
12108
12202
|
source: image.source
|
|
12109
12203
|
};
|
|
12110
12204
|
}
|
|
12111
|
-
function
|
|
12112
|
-
const
|
|
12113
|
-
|
|
12114
|
-
|
|
12115
|
-
slug: video._id,
|
|
12116
|
-
title,
|
|
12117
|
-
body: video.description,
|
|
12118
|
-
tags,
|
|
12119
|
-
thumbnailUrl: video.thumbnailUrl,
|
|
12120
|
-
muxPlaybackId: video.muxPlaybackId,
|
|
12121
|
-
playbackUrl: video.muxPlaybackId ? `https://stream.mux.com/${video.muxPlaybackId}.m3u8` : void 0,
|
|
12122
|
-
duration: video.duration,
|
|
12123
|
-
width: video.width,
|
|
12124
|
-
height: video.height,
|
|
12125
|
-
aspectRatio: video.aspectRatio,
|
|
12126
|
-
source: video.source
|
|
12127
|
-
};
|
|
12128
|
-
}
|
|
12129
|
-
async function updateImageMetadata(deps, args) {
|
|
12130
|
-
await deps.post("/api/images/update-description", {
|
|
12131
|
-
imageId: args.imageId,
|
|
12132
|
-
name: args.title,
|
|
12133
|
-
description: args.body,
|
|
12134
|
-
tags: args.tags
|
|
12135
|
-
});
|
|
12136
|
-
}
|
|
12137
|
-
function createVideoUpload(deps) {
|
|
12138
|
-
return deps.post("/api/videos/upload", {});
|
|
12139
|
-
}
|
|
12140
|
-
function getVideo(deps, videoId) {
|
|
12141
|
-
return deps.get("/api/videos/get", { id: videoId });
|
|
12142
|
-
}
|
|
12143
|
-
async function updateVideoMetadata(deps, args) {
|
|
12144
|
-
await deps.post("/api/videos/update-description", {
|
|
12145
|
-
videoId: args.videoId,
|
|
12146
|
-
name: args.title,
|
|
12147
|
-
description: args.body,
|
|
12148
|
-
tags: args.tags
|
|
12149
|
-
});
|
|
12150
|
-
}
|
|
12151
|
-
async function waitForReadyVideo(deps, videoId, opts = {}) {
|
|
12152
|
-
const timeoutMs = opts.timeoutMs ?? videoProcessingTimeoutMs;
|
|
12153
|
-
const pollIntervalMs = opts.pollIntervalMs ?? videoReadyPollIntervalMs;
|
|
12154
|
-
const deadline = Date.now() + timeoutMs;
|
|
12155
|
-
let lastStatus = "unknown";
|
|
12156
|
-
while (Date.now() <= deadline) {
|
|
12157
|
-
const video = await getVideo(deps, videoId);
|
|
12158
|
-
lastStatus = video.status ?? "unknown";
|
|
12159
|
-
if (video.status === "ready") {
|
|
12160
|
-
return video;
|
|
12161
|
-
}
|
|
12162
|
-
if (video.status === "error") {
|
|
12163
|
-
throw new ApiError(
|
|
12164
|
-
"INTERNAL_ERROR",
|
|
12165
|
-
`Video processing failed for videoId ${videoId}: ${video.errorMessage ?? "unknown error"}`
|
|
12166
|
-
);
|
|
12167
|
-
}
|
|
12168
|
-
await deps.sleep(pollIntervalMs);
|
|
12169
|
-
}
|
|
12170
|
-
throw new ApiError("TIMEOUT", `Video was not ready before timeout; videoId: ${videoId}; last status: ${lastStatus}`);
|
|
12171
|
-
}
|
|
12172
|
-
async function uploadLocalVideo(args, deps) {
|
|
12173
|
-
const { uploadUrl, videoId } = await createVideoUpload(deps);
|
|
12174
|
-
const fileBuffer = await deps.readFile(args.file);
|
|
12175
|
-
const uploadResponse = await deps.fetch(uploadUrl, {
|
|
12176
|
-
method: "PUT",
|
|
12177
|
-
headers: { "Content-Type": args.contentType },
|
|
12178
|
-
body: fileBuffer
|
|
12179
|
-
});
|
|
12180
|
-
if (!uploadResponse.ok) {
|
|
12181
|
-
throw new ApiError(
|
|
12182
|
-
"INTERNAL_ERROR",
|
|
12183
|
-
`Mux upload failed: HTTP ${uploadResponse.status} ${uploadResponse.statusText}`
|
|
12184
|
-
);
|
|
12205
|
+
async function publishCreative(args, deps = defaultImageApiDeps) {
|
|
12206
|
+
const title = args.title.trim();
|
|
12207
|
+
if (!title) {
|
|
12208
|
+
throw new ApiError("VALIDATION_ERROR", "--title is required");
|
|
12185
12209
|
}
|
|
12186
|
-
|
|
12187
|
-
}
|
|
12188
|
-
async function publishCreativeImage(args, deps) {
|
|
12210
|
+
const contentType = detectCreativeContentType(args.file);
|
|
12189
12211
|
const upload = await uploadLocalImage(
|
|
12190
12212
|
{
|
|
12191
12213
|
file: args.file,
|
|
12192
|
-
contentType
|
|
12214
|
+
contentType,
|
|
12193
12215
|
source: "ai_generated",
|
|
12194
|
-
descriptionContext: args.
|
|
12216
|
+
descriptionContext: args.context ?? `Static ad creative: ${title}`
|
|
12195
12217
|
},
|
|
12196
12218
|
deps
|
|
12197
12219
|
);
|
|
12198
12220
|
const readyImage = await waitForReadyImage(deps, upload.imageId, { timeoutMs: imageProcessingTimeoutMs });
|
|
12199
|
-
|
|
12200
|
-
|
|
12221
|
+
await updateImageTags(deps, {
|
|
12222
|
+
imageIds: [upload.imageId],
|
|
12223
|
+
addTags: [creativeTag],
|
|
12224
|
+
removeTags: []
|
|
12225
|
+
});
|
|
12201
12226
|
const taggedImage = await getImage(deps, upload.imageId);
|
|
12202
|
-
return {
|
|
12203
|
-
imageId: upload.imageId,
|
|
12204
|
-
reference: imageToCreativeReference({ ...readyImage, ...taggedImage }, args.title)
|
|
12205
|
-
};
|
|
12206
|
-
}
|
|
12207
|
-
async function publishCreativeVideo(args, deps) {
|
|
12208
|
-
const { videoId } = await uploadLocalVideo({ file: args.file, contentType: args.contentType }, deps);
|
|
12209
|
-
const readyVideo = await waitForReadyVideo(deps, videoId);
|
|
12210
|
-
const tags = uniqueTags([...readyVideo.tags, ...creativeTags]);
|
|
12211
|
-
await updateVideoMetadata(deps, { videoId, title: args.title, body: args.body, tags });
|
|
12212
|
-
const taggedVideo = await getVideo(deps, videoId);
|
|
12213
|
-
return { videoId, reference: videoToCreativeReference(taggedVideo, args.title) };
|
|
12214
|
-
}
|
|
12215
|
-
function publishCreative(args, deps = defaultCreativePublishDeps) {
|
|
12216
|
-
try {
|
|
12217
|
-
const metadata = requiredMetadata(args);
|
|
12218
|
-
const contentType = detectCreativeContentType(args.file);
|
|
12219
|
-
if (isVideoContentType(contentType)) {
|
|
12220
|
-
return publishCreativeVideo({ file: args.file, ...metadata, contentType }, deps);
|
|
12221
|
-
}
|
|
12222
|
-
return publishCreativeImage({ file: args.file, ...metadata, contentType }, deps);
|
|
12223
|
-
} catch (error) {
|
|
12224
|
-
return Promise.reject(error);
|
|
12225
|
-
}
|
|
12227
|
+
return { imageId: upload.imageId, reference: imageToCreativeReference({ ...readyImage, ...taggedImage }, title) };
|
|
12226
12228
|
}
|
|
12227
12229
|
var publishCommand = defineCommand87({
|
|
12228
12230
|
meta: {
|
|
12229
12231
|
name: "publish",
|
|
12230
|
-
description: "Publish a final creative image
|
|
12232
|
+
description: "Publish a final static creative image to Baker Images, deterministically tag it as creative, and print the image reference JSON."
|
|
12231
12233
|
},
|
|
12232
12234
|
args: {
|
|
12233
|
-
file: { type: "positional", description: "Local PNG/JPG/WebP
|
|
12235
|
+
file: { type: "positional", description: "Local PNG/JPG/WebP creative image path", required: false },
|
|
12234
12236
|
title: { type: "string", description: "Human title for the creative output", required: false },
|
|
12235
|
-
|
|
12237
|
+
context: { type: "string", description: "Optional describe context for the image row", required: false }
|
|
12236
12238
|
},
|
|
12237
12239
|
run: async ({ args }) => {
|
|
12238
12240
|
try {
|
|
12239
12241
|
const file = args.file;
|
|
12240
12242
|
const title = args.title;
|
|
12241
|
-
const body = args.body;
|
|
12242
12243
|
if (!file) {
|
|
12243
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "
|
|
12244
|
+
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "Image path is required" } });
|
|
12244
12245
|
process.exit(1);
|
|
12245
12246
|
}
|
|
12246
12247
|
if (!title) {
|
|
12247
12248
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--title is required" } });
|
|
12248
12249
|
process.exit(1);
|
|
12249
12250
|
}
|
|
12250
|
-
|
|
12251
|
-
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--body is required" } });
|
|
12252
|
-
process.exit(1);
|
|
12253
|
-
}
|
|
12254
|
-
const data = await publishCreative({ file, title, body });
|
|
12251
|
+
const data = await publishCreative({ file, title, context: args.context });
|
|
12255
12252
|
writeJson({ ok: true, data });
|
|
12256
12253
|
} catch (err) {
|
|
12257
12254
|
if (err instanceof ApiError) {
|
|
@@ -12268,13 +12265,12 @@ var publishCommand = defineCommand87({
|
|
|
12268
12265
|
var creativesCommand3 = defineCommand88({
|
|
12269
12266
|
meta: {
|
|
12270
12267
|
name: "creatives",
|
|
12271
|
-
description: `Publish ad creatives as first-class Baker outputs.
|
|
12268
|
+
description: `Publish static ad creatives as first-class Baker outputs.
|
|
12272
12269
|
|
|
12273
|
-
|
|
12274
|
-
baker creatives publish ./canvas/run/final.png --title "
|
|
12275
|
-
Angle adapted: Client-safe angle"
|
|
12270
|
+
Static creative handoff:
|
|
12271
|
+
baker creatives publish ./canvas/run/final.png --title "Spring Offer Static Ad"
|
|
12276
12272
|
|
|
12277
|
-
Publishing
|
|
12273
|
+
Publishing uploads the image to the Company image library, applies the official creative tag, and returns an image reference for chat previews.`
|
|
12278
12274
|
},
|
|
12279
12275
|
subCommands: {
|
|
12280
12276
|
publish: publishCommand
|
|
@@ -12456,7 +12452,7 @@ Examples:
|
|
|
12456
12452
|
});
|
|
12457
12453
|
|
|
12458
12454
|
// src/commands/ga4/query.ts
|
|
12459
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
12455
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
|
|
12460
12456
|
import { resolve as resolve2 } from "path";
|
|
12461
12457
|
import { defineCommand as defineCommand91 } from "citty";
|
|
12462
12458
|
|
|
@@ -12530,7 +12526,7 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
12530
12526
|
const fields = extractFields2(rows);
|
|
12531
12527
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
12532
12528
|
if (ext === "csv") {
|
|
12533
|
-
if (!append || !
|
|
12529
|
+
if (!append || !existsSync5(filePath)) {
|
|
12534
12530
|
writeFileSync4(filePath, `${toCsvRow(fields)}
|
|
12535
12531
|
`, "utf-8");
|
|
12536
12532
|
}
|
|
@@ -12541,13 +12537,13 @@ function writeRowsToFile2(filePath, rows, append) {
|
|
|
12541
12537
|
const lines = rows.map((row) => JSON.stringify(row));
|
|
12542
12538
|
const content = `${lines.join("\n")}
|
|
12543
12539
|
`;
|
|
12544
|
-
if (append &&
|
|
12540
|
+
if (append && existsSync5(filePath)) {
|
|
12545
12541
|
appendFileSync2(filePath, content, "utf-8");
|
|
12546
12542
|
} else {
|
|
12547
12543
|
writeFileSync4(filePath, content, "utf-8");
|
|
12548
12544
|
}
|
|
12549
|
-
} else if (append &&
|
|
12550
|
-
const existing = JSON.parse(
|
|
12545
|
+
} else if (append && existsSync5(filePath)) {
|
|
12546
|
+
const existing = JSON.parse(readFileSync7(filePath, "utf-8"));
|
|
12551
12547
|
writeFileSync4(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
12552
12548
|
} else {
|
|
12553
12549
|
writeFileSync4(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -12687,7 +12683,7 @@ Examples:
|
|
|
12687
12683
|
import { defineCommand as defineCommand96 } from "citty";
|
|
12688
12684
|
|
|
12689
12685
|
// src/commands/gsc/query.ts
|
|
12690
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
12686
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
|
|
12691
12687
|
import { resolve as resolve3 } from "path";
|
|
12692
12688
|
import { defineCommand as defineCommand93 } from "citty";
|
|
12693
12689
|
|
|
@@ -12816,7 +12812,7 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
12816
12812
|
const fields = extractFields3(rows);
|
|
12817
12813
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
12818
12814
|
if (ext === "csv") {
|
|
12819
|
-
if (!append || !
|
|
12815
|
+
if (!append || !existsSync6(filePath)) {
|
|
12820
12816
|
writeFileSync5(filePath, `${toCsvRow(fields)}
|
|
12821
12817
|
`, "utf-8");
|
|
12822
12818
|
}
|
|
@@ -12826,13 +12822,13 @@ function writeRowsToFile3(filePath, rows, append) {
|
|
|
12826
12822
|
} else if (ext === "jsonl") {
|
|
12827
12823
|
const content = `${rows.map((row) => JSON.stringify(row)).join("\n")}
|
|
12828
12824
|
`;
|
|
12829
|
-
if (append &&
|
|
12825
|
+
if (append && existsSync6(filePath)) {
|
|
12830
12826
|
appendFileSync3(filePath, content, "utf-8");
|
|
12831
12827
|
} else {
|
|
12832
12828
|
writeFileSync5(filePath, content, "utf-8");
|
|
12833
12829
|
}
|
|
12834
|
-
} else if (append &&
|
|
12835
|
-
const existing = JSON.parse(
|
|
12830
|
+
} else if (append && existsSync6(filePath)) {
|
|
12831
|
+
const existing = JSON.parse(readFileSync8(filePath, "utf-8"));
|
|
12836
12832
|
writeFileSync5(filePath, JSON.stringify([...existing, ...rows], null, 2), "utf-8");
|
|
12837
12833
|
} else {
|
|
12838
12834
|
writeFileSync5(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
@@ -13112,7 +13108,7 @@ function cropSprite(input, region) {
|
|
|
13112
13108
|
// src/lib/image/io.ts
|
|
13113
13109
|
import { randomBytes } from "crypto";
|
|
13114
13110
|
import { glob as fsGlob, readFile as readFile10, rename, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
13115
|
-
import { dirname, extname as
|
|
13111
|
+
import { dirname as dirname2, extname as extname2, join as join4, resolve as resolve4 } from "path";
|
|
13116
13112
|
var REMOTE_RE = /^https?:\/\//i;
|
|
13117
13113
|
var GLOB_RE = /[*?[\]{}]/;
|
|
13118
13114
|
function isRemoteUrl(value) {
|
|
@@ -13158,18 +13154,18 @@ async function isDirectory(path11) {
|
|
|
13158
13154
|
}
|
|
13159
13155
|
}
|
|
13160
13156
|
async function resolveOutputPath(inputPath, outputArg, options) {
|
|
13161
|
-
const base = options.newExtension ? inputPath.slice(0, -
|
|
13157
|
+
const base = options.newExtension ? inputPath.slice(0, -extname2(inputPath).length) + options.newExtension : inputPath;
|
|
13162
13158
|
if (!outputArg) return base;
|
|
13163
13159
|
if (options.multipleInputs || await isDirectory(outputArg)) {
|
|
13164
13160
|
const filename = base.split("/").pop() ?? "out.png";
|
|
13165
|
-
return
|
|
13161
|
+
return join4(outputArg, filename);
|
|
13166
13162
|
}
|
|
13167
13163
|
return outputArg;
|
|
13168
13164
|
}
|
|
13169
13165
|
async function atomicWrite(targetPath, data) {
|
|
13170
13166
|
const absolute = resolve4(targetPath);
|
|
13171
|
-
const dir =
|
|
13172
|
-
const tmp =
|
|
13167
|
+
const dir = dirname2(absolute);
|
|
13168
|
+
const tmp = join4(dir, `.baker-image-${randomBytes(8).toString("hex")}.tmp`);
|
|
13173
13169
|
await writeFile4(tmp, data);
|
|
13174
13170
|
await rename(tmp, absolute);
|
|
13175
13171
|
}
|
|
@@ -17471,7 +17467,7 @@ var tagsCommand4 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
17471
17467
|
|
|
17472
17468
|
// src/commands/videos/upload.ts
|
|
17473
17469
|
import { readFile as readFile12, stat as stat3 } from "fs/promises";
|
|
17474
|
-
import { extname as
|
|
17470
|
+
import { extname as extname3 } from "path";
|
|
17475
17471
|
import { defineCommand as defineCommand147 } from "citty";
|
|
17476
17472
|
var MIME_MAP = {
|
|
17477
17473
|
".mp4": "video/mp4",
|
|
@@ -17499,7 +17495,7 @@ registerSchema({
|
|
|
17499
17495
|
}
|
|
17500
17496
|
});
|
|
17501
17497
|
function detectContentType(filePath) {
|
|
17502
|
-
const ext =
|
|
17498
|
+
const ext = extname3(filePath).toLowerCase();
|
|
17503
17499
|
const mime = MIME_MAP[ext];
|
|
17504
17500
|
if (!mime) {
|
|
17505
17501
|
throw new ApiError("VALIDATION_ERROR", `Cannot detect content type for extension "${ext}". Use --content-type.`);
|
|
@@ -17651,7 +17647,6 @@ var advertisersCommand2 = defineCommand149({
|
|
|
17651
17647
|
|
|
17652
17648
|
// src/commands/winning-ads/search.ts
|
|
17653
17649
|
import { defineCommand as defineCommand150 } from "citty";
|
|
17654
|
-
import { z as z4 } from "zod";
|
|
17655
17650
|
registerSchema({
|
|
17656
17651
|
command: "winning-ads.search",
|
|
17657
17652
|
description: "Search the ad-dna corpus of scored winning ads. Returns a lean shortlist (advertiser, summary, scores, media_url) to pick a reference to reproduce.",
|
|
@@ -17759,38 +17754,6 @@ function buildSearchBody(args) {
|
|
|
17759
17754
|
}
|
|
17760
17755
|
return body;
|
|
17761
17756
|
}
|
|
17762
|
-
function toOutputRecord(value) {
|
|
17763
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
17764
|
-
return {};
|
|
17765
|
-
}
|
|
17766
|
-
return Object.fromEntries(Object.entries(value));
|
|
17767
|
-
}
|
|
17768
|
-
var winningAdsSearchResponseSchema = z4.object({
|
|
17769
|
-
results: z4.array(z4.unknown()).optional(),
|
|
17770
|
-
pool_size: z4.number().nullable().optional(),
|
|
17771
|
-
match_confidence: z4.string().nullable().optional(),
|
|
17772
|
-
ownAdvertiserExclusion: z4.object({
|
|
17773
|
-
status: z4.enum(["applied", "unresolved", "skipped"]),
|
|
17774
|
-
excludedIds: z4.array(z4.string())
|
|
17775
|
-
}).nullable().optional()
|
|
17776
|
-
});
|
|
17777
|
-
function parseWinningAdsSearchResponse(data) {
|
|
17778
|
-
const parsed = winningAdsSearchResponseSchema.safeParse(data);
|
|
17779
|
-
if (!parsed.success) {
|
|
17780
|
-
throw new ApiError("INTERNAL_ERROR", "Invalid winning ads search response");
|
|
17781
|
-
}
|
|
17782
|
-
return parsed.data;
|
|
17783
|
-
}
|
|
17784
|
-
function buildSearchOutputData(data, options) {
|
|
17785
|
-
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
17786
|
-
const results = rawResults.map((r) => winningAdNormalizer(toOutputRecord(r), options.full));
|
|
17787
|
-
return {
|
|
17788
|
-
results,
|
|
17789
|
-
pool_size: data?.pool_size ?? null,
|
|
17790
|
-
match_confidence: data?.match_confidence ?? null,
|
|
17791
|
-
ownAdvertiserExclusion: data?.ownAdvertiserExclusion ?? null
|
|
17792
|
-
};
|
|
17793
|
-
}
|
|
17794
17757
|
var searchCommand4 = defineCommand150({
|
|
17795
17758
|
meta: {
|
|
17796
17759
|
name: "search",
|
|
@@ -17869,12 +17832,19 @@ var searchCommand4 = defineCommand150({
|
|
|
17869
17832
|
});
|
|
17870
17833
|
process.exit(1);
|
|
17871
17834
|
}
|
|
17872
|
-
const data =
|
|
17835
|
+
const data = await apiPost(
|
|
17836
|
+
"/api/winning-ads/search",
|
|
17837
|
+
body
|
|
17838
|
+
);
|
|
17873
17839
|
const output = args.output || "json";
|
|
17874
17840
|
const full = args.full;
|
|
17875
17841
|
const rawResults = Array.isArray(data?.results) ? data.results : [];
|
|
17876
17842
|
if (output === "json") {
|
|
17877
|
-
|
|
17843
|
+
const results = rawResults.map((r) => winningAdNormalizer(r, full));
|
|
17844
|
+
writeJson({
|
|
17845
|
+
ok: true,
|
|
17846
|
+
data: { results, pool_size: data?.pool_size ?? null, match_confidence: data?.match_confidence ?? null }
|
|
17847
|
+
});
|
|
17878
17848
|
return;
|
|
17879
17849
|
}
|
|
17880
17850
|
writeOutput(
|
|
@@ -17920,7 +17890,7 @@ Examples:
|
|
|
17920
17890
|
});
|
|
17921
17891
|
|
|
17922
17892
|
// src/version.ts
|
|
17923
|
-
import { readFileSync as
|
|
17893
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
17924
17894
|
function packageJsonUrl() {
|
|
17925
17895
|
return new URL("../package.json", import.meta.url);
|
|
17926
17896
|
}
|
|
@@ -17932,7 +17902,7 @@ function parsePackageVersion(raw) {
|
|
|
17932
17902
|
throw new Error("Invalid CLI package.json: missing version");
|
|
17933
17903
|
}
|
|
17934
17904
|
function getCliVersion() {
|
|
17935
|
-
return parsePackageVersion(
|
|
17905
|
+
return parsePackageVersion(readFileSync9(packageJsonUrl(), "utf8"));
|
|
17936
17906
|
}
|
|
17937
17907
|
|
|
17938
17908
|
// src/cli.ts
|