@koda-sl/baker-cli 0.343.0-dev.69293e822 → 0.343.0-dev.acf96fa0f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -609,16 +609,11 @@ baker ads google keywords update <criterion-id> --customer-id 1234567890 --clear
609
609
  baker ads google ads create --customer-id 1234567890 --ad-group-ref g_temp_<adgroup> \
610
610
  --headlines "Fast Widgets,Buy Online,Free Shipping" --descriptions "Best widgets around.,Ships tomorrow." \
611
611
  --final-url https://example.com
612
- # Copy with commas in it — repeat the flag once per item (or quote the item: '"Fast, free quotes",Book today')
613
- baker ads google ads create --customer-id 1234567890 --ad-group-ref g_temp_<adgroup> \
614
- --headlines "Fast Widgets,Buy Online,Free Shipping" \
615
- --descriptions "Calls, messages and bookings in one place." --descriptions "Ships tomorrow, free." \
616
- --final-url https://example.com
617
612
  # Responsive display ad — images are fields on the ad; register each image as an asset first (returns a g_temp_* ref)
618
613
  baker ads google assets create --customer-id 1234567890 --file '{"type":"image","imageId":"<baker_image_id>","name":"Hero"}'
619
614
  baker ads google ads create --customer-id 1234567890 --ad-group-ref g_temp_<adgroup> --format responsiveDisplay \
620
615
  --headlines "Come back and save" --long-headline "Finish signing up and get 20% off" \
621
- --descriptions '"Fast setup, no card required"' --business-name "Acme" --final-url https://example.com \
616
+ --descriptions "Fast setup, no card required" --business-name "Acme" --final-url https://example.com \
622
617
  --marketing-images g_temp_<img_landscape> --square-marketing-images g_temp_<img_square> --logo-images g_temp_<img_logo>
623
618
  # Video ad — the YouTube video is its own asset first, then referenced by --video-assets
624
619
  baker ads google assets create --customer-id 1234567890 --file '{"type":"youtubeVideo","youtubeVideoId":"dQw4w9WgXcQ"}'
@@ -8,7 +8,11 @@
8
8
  "default_duration": 3,
9
9
  "inputs": {},
10
10
  "params": {
11
- "logo_svg": { "kind": "string", "default": "", "description": "Raw inline <svg>…</svg> wordmark with fill set to text_color (optional)." },
11
+ "logo_svg": {
12
+ "kind": "string",
13
+ "default": "",
14
+ "description": "Raw inline <svg>…</svg> wordmark with fill set to text_color (optional)."
15
+ },
12
16
  "headline": { "kind": "string", "required": true, "description": "Closing line." },
13
17
  "cta_text": { "kind": "string", "default": "", "description": "Call-to-action pill label (optional)." },
14
18
  "bg_color": { "kind": "color", "default": "#0b1020" },
@@ -9,10 +9,20 @@
9
9
  "inputs": {},
10
10
  "params": {
11
11
  "title": { "kind": "string", "default": "", "description": "Optional heading above the list." },
12
- "features": { "kind": "json", "required": true, "description": "Array of 1–6 short labels, e.g. [\"No setup fees\", \"Cancel anytime\"]." },
12
+ "features": {
13
+ "kind": "json",
14
+ "required": true,
15
+ "description": "Array of 1–6 short labels, e.g. [\"No setup fees\", \"Cancel anytime\"]."
16
+ },
13
17
  "text_color": { "kind": "color", "default": "#0b1020" },
14
18
  "accent_color": { "kind": "color", "default": "#1f9d57", "description": "Check-circle fill." },
15
19
  "check_color": { "kind": "color", "default": "#ffffff", "description": "The check mark inside the circle." },
16
- "stagger_s": { "kind": "number", "default": 0.18, "min": 0.02, "max": 1, "description": "Seconds between each item." }
20
+ "stagger_s": {
21
+ "kind": "number",
22
+ "default": 0.18,
23
+ "min": 0.02,
24
+ "max": 1,
25
+ "description": "Seconds between each item."
26
+ }
17
27
  }
18
28
  }
@@ -13,6 +13,12 @@
13
13
  "bar_color": { "kind": "color", "default": "#0b1020" },
14
14
  "text_color": { "kind": "color", "default": "#ffffff" },
15
15
  "accent_color": { "kind": "color", "default": "#5b8cff", "description": "The leading accent block." },
16
- "from_bottom_px": { "kind": "integer", "default": 220, "min": 0, "max": 1600, "description": "Distance of the bar from the bottom edge." }
16
+ "from_bottom_px": {
17
+ "kind": "integer",
18
+ "default": 220,
19
+ "min": 0,
20
+ "max": 1600,
21
+ "description": "Distance of the bar from the bottom edge."
22
+ }
17
23
  }
18
24
  }
@@ -15,12 +15,34 @@
15
15
  }
16
16
  },
17
17
  "params": {
18
- "headline": { "kind": "string", "default": "", "description": "Big line on the content stage (what the presenter is showing)." },
19
- "claim": { "kind": "string", "default": "", "description": "Short proof/claim on the floating glass card (optional)." },
18
+ "headline": {
19
+ "kind": "string",
20
+ "default": "",
21
+ "description": "Big line on the content stage (what the presenter is showing)."
22
+ },
23
+ "claim": {
24
+ "kind": "string",
25
+ "default": "",
26
+ "description": "Short proof/claim on the floating glass card (optional)."
27
+ },
20
28
  "caption": { "kind": "string", "default": "", "description": "A caption line in the lower band (optional)." },
21
- "pip_at_s": { "kind": "number", "default": 2, "min": 0, "max": 30, "description": "When the presenter shrinks to the corner pill." },
22
- "bg_color": { "kind": "color", "default": "#0b1020", "description": "Content-stage background (behind the presenter)." },
29
+ "pip_at_s": {
30
+ "kind": "number",
31
+ "default": 2,
32
+ "min": 0,
33
+ "max": 30,
34
+ "description": "When the presenter shrinks to the corner pill."
35
+ },
36
+ "bg_color": {
37
+ "kind": "color",
38
+ "default": "#0b1020",
39
+ "description": "Content-stage background (behind the presenter)."
40
+ },
23
41
  "text_color": { "kind": "color", "default": "#ffffff" },
24
- "accent_color": { "kind": "color", "default": "#5b8cff", "description": "Headline accent + caption underline + pill ring tint." }
42
+ "accent_color": {
43
+ "kind": "color",
44
+ "default": "#5b8cff",
45
+ "description": "Headline accent + caption underline + pill ring tint."
46
+ }
25
47
  }
26
48
  }
package/dist/cli.js CHANGED
@@ -17043,101 +17043,6 @@ Examples:
17043
17043
  // src/commands/ads/google/write-commands.ts
17044
17044
  import { defineCommand as defineCommand31 } from "citty";
17045
17045
 
17046
- // src/commands/ads/google/ad-copy-flags.ts
17047
- var AD_COPY_LIST_FLAGS = ["headlines", "descriptions", "long-headlines"];
17048
- var AD_COPY_LIST_USAGE = `repeat the flag once per item (safe for copy with commas), or pass one comma-separated list and wrap an item that contains a comma in double quotes: '"Fast, free quotes",Book today'`;
17049
- function skipBlanks(value, at) {
17050
- let i = at;
17051
- while (value[i] === " " || value[i] === " ") i++;
17052
- return i;
17053
- }
17054
- function readQuotedField(value, open, flag) {
17055
- let text2 = "";
17056
- let j = open + 1;
17057
- while (!(value[j] === '"' && value[j + 1] !== '"')) {
17058
- if (j >= value.length) {
17059
- failWriteValidation(`--${flag} has a quote with no closing quote: ${value} \u2014 ${AD_COPY_LIST_USAGE}`);
17060
- }
17061
- text2 += value[j];
17062
- j += value[j] === '"' ? 2 : 1;
17063
- }
17064
- const after = skipBlanks(value, j + 1);
17065
- if (after < value.length && value[after] !== ",") {
17066
- failWriteValidation(
17067
- `--${flag}: text follows the closing quote of "${text2}" \u2014 a quoted item must end at a comma. To put a quote inside an item, double it ("") or ${AD_COPY_LIST_USAGE}`
17068
- );
17069
- }
17070
- return { text: text2, next: after + 1 };
17071
- }
17072
- function splitQuotedList(value, flag) {
17073
- const fields = [];
17074
- let i = 0;
17075
- while (i <= value.length) {
17076
- const start = skipBlanks(value, i);
17077
- if (value[start] === '"') {
17078
- const { text: text2, next } = readQuotedField(value, start, flag);
17079
- fields.push({ text: text2, quoted: true });
17080
- i = next;
17081
- } else {
17082
- const comma = value.indexOf(",", start);
17083
- const end = comma === -1 ? value.length : comma;
17084
- fields.push({ text: value.slice(start, end), quoted: false });
17085
- i = end + 1;
17086
- }
17087
- }
17088
- const several = fields.length > 1;
17089
- return fields.map((field) => ({ text: field.text.trim(), splitAtComma: several && !field.quoted }));
17090
- }
17091
- function jsonStringArray(value) {
17092
- if (!value.startsWith("[")) return void 0;
17093
- try {
17094
- const parsed = JSON.parse(value);
17095
- return Array.isArray(parsed) && parsed.every((v) => typeof v === "string") ? parsed : void 0;
17096
- } catch {
17097
- return void 0;
17098
- }
17099
- }
17100
- function parseCopyList(value, flag) {
17101
- let items;
17102
- if (Array.isArray(value)) {
17103
- items = value.filter((v) => typeof v === "string").map((v) => ({ text: v.trim(), splitAtComma: false }));
17104
- } else if (typeof value === "string") {
17105
- const trimmed = value.trim();
17106
- const json = jsonStringArray(trimmed);
17107
- items = json ? json.map((v) => ({ text: v.trim(), splitAtComma: false })) : splitQuotedList(trimmed, flag);
17108
- } else {
17109
- return void 0;
17110
- }
17111
- const kept = items.filter((item) => item.text.length > 0);
17112
- return kept.length > 0 ? kept : void 0;
17113
- }
17114
- function copyListFlag(value, flag) {
17115
- return parseCopyList(value, flag)?.map((item) => item.text);
17116
- }
17117
- function withRepeatedCopyFlags(args5, rawArgs) {
17118
- const out = { ...args5 };
17119
- for (const flag of AD_COPY_LIST_FLAGS) {
17120
- const values = repeatedFlagValues(rawArgs ?? [], flag);
17121
- if (values.length > 1) {
17122
- out[flag] = values;
17123
- }
17124
- }
17125
- return out;
17126
- }
17127
- function copyListSplitHints(args5) {
17128
- const hints2 = [];
17129
- for (const flag of AD_COPY_LIST_FLAGS) {
17130
- const items = parseCopyList(args5[flag], flag) ?? [];
17131
- const fragments = items.filter((item, index) => index > 0 && item.splitAtComma && new RegExp("^\\p{Ll}", "u").test(item.text));
17132
- if (fragments.length > 0) {
17133
- hints2.push(
17134
- `--${flag}: ${fragments.map((f) => `"${f.text}"`).join(", ")} starts in lowercase \u2014 it looks like the end of one item cut at a comma. Check the staged copy; if it was one item, re-stage and ${AD_COPY_LIST_USAGE}.`
17135
- );
17136
- }
17137
- }
17138
- return hints2;
17139
- }
17140
-
17141
17046
  // src/commands/ads/google/conversion-upload-command.ts
17142
17047
  import { readFileSync as readFileSync4 } from "fs";
17143
17048
  import { defineCommand as defineCommand30 } from "citty";
@@ -18193,10 +18098,10 @@ var keywordListsCommand = defineCommand31({
18193
18098
  }
18194
18099
  });
18195
18100
  function rsaContentFromFlags(args5) {
18196
- const headlines = copyListFlag(args5.headlines, "headlines");
18197
- const descriptions = copyListFlag(args5.descriptions, "descriptions");
18101
+ const headlines = listFlag(args5.headlines);
18102
+ const descriptions = listFlag(args5.descriptions);
18198
18103
  if (!headlines || !descriptions) {
18199
- failWriteValidation("responsive search ads need --headlines and --descriptions, or use --file");
18104
+ failWriteValidation("responsive search ads need --headlines and --descriptions (comma-separated), or use --file");
18200
18105
  }
18201
18106
  const finalUrls = listFlag(args5["final-url"]);
18202
18107
  if (!finalUrls) {
@@ -18216,11 +18121,11 @@ function rdaContentFromFlags(args5, base) {
18216
18121
  format: "responsiveDisplay",
18217
18122
  ...base !== null && typeof base === "object" && !Array.isArray(base) ? base : {}
18218
18123
  };
18219
- const headlines = copyListFlag(args5.headlines, "headlines");
18124
+ const headlines = listFlag(args5.headlines);
18220
18125
  if (headlines) {
18221
18126
  content.headlines = headlines.map((text2) => ({ text: text2 }));
18222
18127
  }
18223
- const descriptions = copyListFlag(args5.descriptions, "descriptions");
18128
+ const descriptions = listFlag(args5.descriptions);
18224
18129
  if (descriptions) {
18225
18130
  content.descriptions = descriptions.map((text2) => ({ text: text2 }));
18226
18131
  }
@@ -18271,11 +18176,11 @@ function demandGenContentFromFlags(args5, base) {
18271
18176
  if (typeof args5["ad-name"] === "string") {
18272
18177
  content.name = args5["ad-name"];
18273
18178
  }
18274
- const headlines = copyListFlag(args5.headlines, "headlines");
18179
+ const headlines = listFlag(args5.headlines);
18275
18180
  if (headlines) {
18276
18181
  content.headlines = headlines.map((text2) => ({ text: text2 }));
18277
18182
  }
18278
- const descriptions = copyListFlag(args5.descriptions, "descriptions");
18183
+ const descriptions = listFlag(args5.descriptions);
18279
18184
  if (descriptions) {
18280
18185
  content.descriptions = descriptions.map((text2) => ({ text: text2 }));
18281
18186
  }
@@ -18308,15 +18213,15 @@ function demandGenVideoContentFromFlags(args5, base) {
18308
18213
  if (typeof args5["ad-name"] === "string") {
18309
18214
  content.name = args5["ad-name"];
18310
18215
  }
18311
- const headlines = copyListFlag(args5.headlines, "headlines");
18216
+ const headlines = listFlag(args5.headlines);
18312
18217
  if (headlines) {
18313
18218
  content.headlines = headlines.map((text2) => ({ text: text2 }));
18314
18219
  }
18315
- const longHeadlines = copyListFlag(args5["long-headlines"], "long-headlines");
18220
+ const longHeadlines = listFlag(args5["long-headlines"]);
18316
18221
  if (longHeadlines) {
18317
18222
  content.longHeadlines = longHeadlines.map((text2) => ({ text: text2 }));
18318
18223
  }
18319
- const descriptions = copyListFlag(args5.descriptions, "descriptions");
18224
+ const descriptions = listFlag(args5.descriptions);
18320
18225
  if (descriptions) {
18321
18226
  content.descriptions = descriptions.map((text2) => ({ text: text2 }));
18322
18227
  }
@@ -18346,11 +18251,11 @@ function appContentFromFlags(args5, base) {
18346
18251
  format: "app",
18347
18252
  ...base !== null && typeof base === "object" && !Array.isArray(base) ? base : {}
18348
18253
  };
18349
- const headlines = copyListFlag(args5.headlines, "headlines");
18254
+ const headlines = listFlag(args5.headlines);
18350
18255
  if (headlines) {
18351
18256
  content.headlines = headlines.map((text2) => ({ text: text2 }));
18352
18257
  }
18353
- const descriptions = copyListFlag(args5.descriptions, "descriptions");
18258
+ const descriptions = listFlag(args5.descriptions);
18354
18259
  if (descriptions) {
18355
18260
  content.descriptions = descriptions.map((text2) => ({ text: text2 }));
18356
18261
  }
@@ -18452,13 +18357,10 @@ var adContentArgs = {
18452
18357
  type: "string",
18453
18358
  description: "responsiveSearch (default) | responsiveDisplay | call | app | video | demandGen | demandGenVideo"
18454
18359
  },
18455
- headlines: {
18456
- type: "string",
18457
- description: `Headlines (RSA/RDA/demandGen/demandGenVideo/app) \u2014 ${AD_COPY_LIST_USAGE}`
18458
- },
18360
+ headlines: { type: "string", description: "Comma-separated headlines (RSA/RDA/demandGen/demandGenVideo/app)" },
18459
18361
  descriptions: {
18460
18362
  type: "string",
18461
- description: `Descriptions (RSA/RDA/demandGen/demandGenVideo/app) \u2014 ${AD_COPY_LIST_USAGE}`
18363
+ description: "Comma-separated descriptions (RSA/RDA/demandGen/demandGenVideo/app)"
18462
18364
  },
18463
18365
  path1: { type: "string" },
18464
18366
  path2: { type: "string" },
@@ -18469,7 +18371,7 @@ var adContentArgs = {
18469
18371
  },
18470
18372
  "long-headlines": {
18471
18373
  type: "string",
18472
- description: `Long headlines, up to 5 of 90 chars (demandGenVideo \u2014 no other format has them) \u2014 ${AD_COPY_LIST_USAGE}`
18374
+ description: "Comma-separated long headlines, up to 5 of 90 chars (demandGenVideo \u2014 no other format has them)"
18473
18375
  },
18474
18376
  "business-name": { type: "string", description: "Business name (responsiveDisplay/demandGen/demandGenVideo)" },
18475
18377
  "marketing-images": {
@@ -18520,22 +18422,16 @@ var adsCommand = defineCommand31({
18520
18422
  ...adContentArgs,
18521
18423
  status: { type: "string" }
18522
18424
  },
18523
- run: async ({ args: parsedArgs, rawArgs }) => {
18524
- const args5 = withRepeatedCopyFlags(parsedArgs, rawArgs);
18425
+ run: async ({ args: args5 }) => {
18525
18426
  const customerId = requireCustomerId(args5);
18526
18427
  const file = loadJsonFileArg(args5.file);
18527
18428
  const format = args5.format ?? "responsiveSearch";
18528
18429
  const content = adContentFromFlags(args5, format, file.content);
18529
- await stageCreate(
18530
- "google.ad.create",
18531
- customerId,
18532
- {
18533
- adGroup: requireStringFlag(args5["ad-group-ref"] ?? file.adGroup, "--ad-group-ref"),
18534
- status: args5.status ?? file.status,
18535
- content
18536
- },
18537
- copyListSplitHints(args5)
18538
- );
18430
+ await stageCreate("google.ad.create", customerId, {
18431
+ adGroup: requireStringFlag(args5["ad-group-ref"] ?? file.adGroup, "--ad-group-ref"),
18432
+ status: args5.status ?? file.status,
18433
+ content
18434
+ });
18539
18435
  }
18540
18436
  }),
18541
18437
  update: defineCommand31({
@@ -18544,8 +18440,7 @@ var adsCommand = defineCommand31({
18544
18440
  description: "Stage an ad update. Any content change needs --format plus EVERY required field of that format (or --file with the complete content) \u2014 a field you send replaces its current value wholesale, so a list you pass must already include the entries you want to keep. Optional asset lists you omit entirely are left untouched on the ad. Status-only changes need neither --format nor content flags."
18545
18441
  },
18546
18442
  args: { ...customerIdArg, ...fileArg, ...adContentArgs, status: { type: "string" } },
18547
- run: async ({ args: parsedArgs, rawArgs }) => {
18548
- const args5 = withRepeatedCopyFlags(parsedArgs, rawArgs);
18443
+ run: async ({ args: args5 }) => {
18549
18444
  const customerId = requireCustomerId(args5);
18550
18445
  const file = loadJsonFileArg(args5.file);
18551
18446
  const format = args5.format;
@@ -18559,8 +18454,7 @@ var adsCommand = defineCommand31({
18559
18454
  await stageUpdate("google.ad.update", customerId, requireTarget(args5, "ad"), payload, [
18560
18455
  ...payload.content !== void 0 ? [
18561
18456
  "Each content field you sent replaces its current value wholesale at publish \u2014 re-check that every headline, description, final URL and asset you want to KEEP is in this payload, not just the ones you changed."
18562
- ] : [],
18563
- ...format ? copyListSplitHints(args5) : []
18457
+ ] : []
18564
18458
  ]);
18565
18459
  }
18566
18460
  }),
@@ -18589,9 +18483,9 @@ var assetGroupsCommand = defineCommand31({
18589
18483
  },
18590
18484
  name: { type: "string", description: "Asset group name" },
18591
18485
  "final-urls": { type: "string", description: "Comma-separated final URLs" },
18592
- headlines: { type: "string", description: `Headlines (3\u201315, \u226430 chars) \u2014 ${AD_COPY_LIST_USAGE}` },
18593
- "long-headlines": { type: "string", description: `Long headlines (1\u20135, \u226490 chars) \u2014 ${AD_COPY_LIST_USAGE}` },
18594
- descriptions: { type: "string", description: `Descriptions (2\u20135, \u226490 chars) \u2014 ${AD_COPY_LIST_USAGE}` },
18486
+ headlines: { type: "string", description: "Comma-separated headlines (3\u201315, \u226430 chars)" },
18487
+ "long-headlines": { type: "string", description: "Comma-separated long headlines (1\u20135, \u226490 chars)" },
18488
+ descriptions: { type: "string", description: "Comma-separated descriptions (2\u20135, \u226490 chars)" },
18595
18489
  "business-name": { type: "string" },
18596
18490
  "image-assets": { type: "string", description: "Comma-separated marketing image asset refs (1.91:1)" },
18597
18491
  "square-image-assets": {
@@ -18605,12 +18499,11 @@ var assetGroupsCommand = defineCommand31({
18605
18499
  "logo-assets": { type: "string", description: "Comma-separated logo image asset refs" },
18606
18500
  status: { type: "string", description: "ENABLED | PAUSED (default PAUSED)" }
18607
18501
  },
18608
- run: async ({ args: parsedArgs, rawArgs }) => {
18609
- const args5 = withRepeatedCopyFlags(parsedArgs, rawArgs);
18502
+ run: async ({ args: args5 }) => {
18610
18503
  const customerId = requireCustomerId(args5);
18611
- const headlines = copyListFlag(args5.headlines, "headlines");
18612
- const longHeadlines = copyListFlag(args5["long-headlines"], "long-headlines");
18613
- const descriptions = copyListFlag(args5.descriptions, "descriptions");
18504
+ const headlines = listFlag(args5.headlines);
18505
+ const longHeadlines = listFlag(args5["long-headlines"]);
18506
+ const descriptions = listFlag(args5.descriptions);
18614
18507
  const payload = mergePayload(loadJsonFileArg(args5.file), {
18615
18508
  campaign: args5["campaign-ref"],
18616
18509
  name: args5.name,
@@ -18625,7 +18518,7 @@ var assetGroupsCommand = defineCommand31({
18625
18518
  logoAssets: listFlag(args5["logo-assets"]),
18626
18519
  status: args5.status
18627
18520
  });
18628
- await stageCreate("google.assetGroup.create", customerId, payload, copyListSplitHints(args5));
18521
+ await stageCreate("google.assetGroup.create", customerId, payload);
18629
18522
  }
18630
18523
  }),
18631
18524
  update: defineCommand31({