@koda-sl/baker-cli 0.392.0-dev.9666ad9b3 → 0.394.0-dev.d28cef496
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 +1 -1
- package/dist/cli.js +122 -30
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -876,7 +876,7 @@ Read the company's ChatGPT Ads account (OpenAI's ads inside ChatGPT conversation
|
|
|
876
876
|
| `conversions` | Pixels (with the pixel id a landing page installs) and conversions, with the campaigns using each |
|
|
877
877
|
| `insights` | Impressions, clicks, spend, CTR, CPC, CPM, conversions, CPA, ROAS — per `--level account\|campaign\|ad_group\|ad`, over `--days N` or `--since/--until`, `--granularity`, `--segment country\|device\|platform\|product` |
|
|
878
878
|
| `campaigns create\|update\|pause\|resume\|archive` | Stage a campaign change: objective, daily or lifetime budget (currency units), schedule, countries and regions included and excluded, audiences, platforms, tracking template, status, the conversions it measures (`--conversion-event-ids`), a catalog (`--catalog-id`) |
|
|
879
|
-
| `ad-groups create\|update\|pause\|resume\|archive` | Stage an ad group change: context hints, bid strategy, max bid, tracking template, product filters, status |
|
|
879
|
+
| `ad-groups create\|update\|pause\|resume\|archive` | Stage an ad group change: context hints, bid strategy, max bid, audience bid adjustments, tracking template, product filters, status |
|
|
880
880
|
| `ads create\|update\|pause\|resume\|archive` | Stage a chat card: title, body, landing page, image and its crop, tracking template, status |
|
|
881
881
|
| `ads create-product` | Stage a catalog ad group's product ad: a title template the catalog's products fill in |
|
|
882
882
|
| `pixels create` | Stage a new website pixel |
|
package/dist/cli.js
CHANGED
|
@@ -33300,7 +33300,13 @@ var imageCropSchema = z31.strictObject({
|
|
|
33300
33300
|
var budgetMicrosSchema = z31.number().int("budgets are integer micros \u2014 \u20AC20.00 is 20000000").min(CHATGPT_LIMITS.budgetMinMicros, "a budget is at least one unit of the account currency");
|
|
33301
33301
|
var bidMicrosSchema = z31.number().int("bids are integer micros \u2014 \u20AC2.50 is 2500000").min(1);
|
|
33302
33302
|
var httpsUrlSchema3 = z31.string().trim().max(CHATGPT_LIMITS.urlMax).url("expected a full URL").refine((value) => value.startsWith("https://"), "ChatGPT Ads needs an https:// address");
|
|
33303
|
-
var
|
|
33303
|
+
var DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
33304
|
+
var LOCAL_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?$/;
|
|
33305
|
+
var ZONED_TIME = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})$/;
|
|
33306
|
+
var isoTimeSchema2 = z31.string().trim().refine(
|
|
33307
|
+
(value) => DATE_ONLY.test(value) || LOCAL_TIME.test(value) || ZONED_TIME.test(value),
|
|
33308
|
+
"a date is YYYY-MM-DD, or YYYY-MM-DDTHH:MM in the account's time zone \u2014 e.g. 2026-10-12"
|
|
33309
|
+
).refine((value) => !Number.isNaN(Date.parse(value)), "that date does not exist").transform((value) => ZONED_TIME.test(value) ? new Date(value).toISOString() : value);
|
|
33304
33310
|
var LAST_SCHEDULABLE_MS = Date.parse("2100-01-01T00:00:00Z");
|
|
33305
33311
|
function notPast(what) {
|
|
33306
33312
|
return isoTimeSchema2.refine((value) => Date.parse(value) > Date.now() - 6e4, `the ${what} is in the past`).refine(
|
|
@@ -33308,7 +33314,7 @@ function notPast(what) {
|
|
|
33308
33314
|
`the ${what} is after 2099, which ChatGPT Ads cannot store`
|
|
33309
33315
|
);
|
|
33310
33316
|
}
|
|
33311
|
-
var startTimeSchema = notPast("start
|
|
33317
|
+
var startTimeSchema = notPast("start");
|
|
33312
33318
|
var endTimeSchema = notPast("end");
|
|
33313
33319
|
var countrySchema = z31.string().trim().regex(/^[A-Za-z]{2}$/, "countries are two-letter codes, e.g. ES").transform((value) => value.toUpperCase()).refine((value) => import_i18n_iso_countries.default.isValid(value), "that is not a country code (ISO 3166-1, e.g. ES)");
|
|
33314
33320
|
var locationIdSchema = z31.string().trim().regex(/^\d+$/, "a region id is the number `baker ads chatgpt locations <place>` returns");
|
|
@@ -33382,6 +33388,13 @@ var conversionEventCreateSchema = z31.strictObject({
|
|
|
33382
33388
|
message: "a custom conversion needs the event name the site sends"
|
|
33383
33389
|
});
|
|
33384
33390
|
}
|
|
33391
|
+
if (p.eventType === "app_installed" || p.eventType === "app_opened") {
|
|
33392
|
+
ctx.addIssue({
|
|
33393
|
+
code: "custom",
|
|
33394
|
+
path: ["eventType"],
|
|
33395
|
+
message: "an app event reaches ChatGPT Ads only through the Conversions API, never a website pixel \u2014 and a conversion cannot be deleted, so it is not staged"
|
|
33396
|
+
});
|
|
33397
|
+
}
|
|
33385
33398
|
if (p.eventType !== "custom" && p.customEventName !== void 0) {
|
|
33386
33399
|
ctx.addIssue({
|
|
33387
33400
|
code: "custom",
|
|
@@ -33422,17 +33435,21 @@ var COUNTRY_NAMES = new Map(
|
|
|
33422
33435
|
CHATGPT_GEOTARGETS.filter(([, , , type]) => type === "country").map(([, name, countryCode2]) => [countryCode2, name])
|
|
33423
33436
|
);
|
|
33424
33437
|
var MAX_PLACES = 2500;
|
|
33438
|
+
function uniqueList(item, min, max) {
|
|
33439
|
+
const list = z31.array(item).min(min);
|
|
33440
|
+
return (max === void 0 ? list : list.max(max)).transform((values) => [...new Set(values)]);
|
|
33441
|
+
}
|
|
33425
33442
|
function targetingFields(min) {
|
|
33426
33443
|
return {
|
|
33427
|
-
countries:
|
|
33444
|
+
countries: uniqueList(countrySchema, min, MAX_PLACES).optional(),
|
|
33428
33445
|
/** Region, market and postal-code ids from ChatGPT Ads' location lookup. */
|
|
33429
|
-
locationIds:
|
|
33446
|
+
locationIds: uniqueList(locationIdSchema, min, MAX_PLACES).optional(),
|
|
33430
33447
|
/** Countries and places the campaign never serves in, even inside an included one. */
|
|
33431
|
-
excludedCountries:
|
|
33432
|
-
excludedLocationIds:
|
|
33448
|
+
excludedCountries: uniqueList(countrySchema, min, MAX_PLACES).optional(),
|
|
33449
|
+
excludedLocationIds: uniqueList(locationIdSchema, min, MAX_PLACES).optional(),
|
|
33433
33450
|
/** Custom audiences the campaign serves only to, and ones it never serves. */
|
|
33434
|
-
audienceIds:
|
|
33435
|
-
excludedAudienceIds:
|
|
33451
|
+
audienceIds: uniqueList(audienceIdSchema, min).optional(),
|
|
33452
|
+
excludedAudienceIds: uniqueList(audienceIdSchema, min).optional(),
|
|
33436
33453
|
platforms: z31.array(z31.enum(CHATGPT_PLATFORMS)).min(1).optional()
|
|
33437
33454
|
};
|
|
33438
33455
|
}
|
|
@@ -33514,6 +33531,21 @@ var campaignUpdateSchema4 = z31.strictObject({
|
|
|
33514
33531
|
checkRunWindow2(p.startTime, p.endTime, ctx);
|
|
33515
33532
|
checkTargeting(p, ctx);
|
|
33516
33533
|
});
|
|
33534
|
+
var audienceBidMultipliersSchema = z31.array(
|
|
33535
|
+
z31.strictObject({
|
|
33536
|
+
audienceId: audienceIdSchema,
|
|
33537
|
+
multiplierMicros: z31.number().int().min(1e5, "a bid adjustment is 0.1\xD7 to 10\xD7 \u2014 100000 to 10000000 micros").max(1e7, "a bid adjustment is 0.1\xD7 to 10\xD7 \u2014 100000 to 10000000 micros")
|
|
33538
|
+
})
|
|
33539
|
+
).max(100);
|
|
33540
|
+
function checkMultipliers(strategy, multipliers, ctx) {
|
|
33541
|
+
if (strategy !== void 0 && strategy !== "fixed_bid" && (multipliers?.length ?? 0) > 0) {
|
|
33542
|
+
ctx.addIssue({
|
|
33543
|
+
code: "custom",
|
|
33544
|
+
path: ["audienceBidMultipliers"],
|
|
33545
|
+
message: "an audience bid adjustment changes a fixed bid \u2014 Maximize Results sets the bid itself"
|
|
33546
|
+
});
|
|
33547
|
+
}
|
|
33548
|
+
}
|
|
33517
33549
|
function checkBidPair2(strategy, maxBid, ctx) {
|
|
33518
33550
|
if (strategy === "fixed_bid" && maxBid === void 0) {
|
|
33519
33551
|
ctx.addIssue({ code: "custom", path: ["maxBidMicros"], message: "a fixed bid needs its amount" });
|
|
@@ -33541,8 +33573,12 @@ var adGroupCreateSchema2 = z31.strictObject({
|
|
|
33541
33573
|
/** Only under a catalog campaign; which of its products this ad group may show. */
|
|
33542
33574
|
productSet: productSetSchema.optional(),
|
|
33543
33575
|
/** The campaign's catalog, filled in at stage time — the product set must name it. */
|
|
33544
|
-
productFeedId: z31.string().trim().min(1).optional()
|
|
33545
|
-
|
|
33576
|
+
productFeedId: z31.string().trim().min(1).optional(),
|
|
33577
|
+
audienceBidMultipliers: audienceBidMultipliersSchema.optional()
|
|
33578
|
+
}).superRefine((p, ctx) => {
|
|
33579
|
+
checkBidPair2(p.bidStrategy, p.maxBidMicros, ctx);
|
|
33580
|
+
checkMultipliers(p.bidStrategy, p.audienceBidMultipliers, ctx);
|
|
33581
|
+
});
|
|
33546
33582
|
var adGroupUpdateSchema2 = z31.strictObject({
|
|
33547
33583
|
name: nameSchema3.optional(),
|
|
33548
33584
|
description: z31.string().trim().max(CHATGPT_LIMITS.nameMax).optional(),
|
|
@@ -33554,9 +33590,12 @@ var adGroupUpdateSchema2 = z31.strictObject({
|
|
|
33554
33590
|
billingEvent: z31.enum(CHATGPT_BILLING_EVENTS).optional(),
|
|
33555
33591
|
/** Replaces the whole product set; `{ filters: [] }` shows the whole catalog. */
|
|
33556
33592
|
productSet: productSetSchema.optional(),
|
|
33557
|
-
productFeedId: z31.string().trim().min(1).optional()
|
|
33593
|
+
productFeedId: z31.string().trim().min(1).optional(),
|
|
33594
|
+
/** Replaces the ad group's adjustments; an empty list clears them. */
|
|
33595
|
+
audienceBidMultipliers: audienceBidMultipliersSchema.optional()
|
|
33558
33596
|
}).superRefine((p, ctx) => {
|
|
33559
33597
|
noEmptyUpdate(p, ctx);
|
|
33598
|
+
checkMultipliers(p.bidStrategy, p.audienceBidMultipliers, ctx);
|
|
33560
33599
|
checkBidPair2(p.bidStrategy, p.maxBidMicros, ctx);
|
|
33561
33600
|
});
|
|
33562
33601
|
var titleSchema = z31.string().trim().refine(
|
|
@@ -34346,7 +34385,7 @@ var SHARED_ARGS = {
|
|
|
34346
34385
|
description: { type: "string", description: "Internal description" },
|
|
34347
34386
|
"context-hints": {
|
|
34348
34387
|
type: "string",
|
|
34349
|
-
description: "When the ad would be useful,
|
|
34388
|
+
description: "When the ad would be useful, short phrases separated by commas \u2014 or by | when a phrase has a comma. ChatGPT's counterpart to keywords, written in the language of the campaign's countries, as people ask ChatGPT. On update it replaces the whole list; none clears it"
|
|
34350
34389
|
},
|
|
34351
34390
|
"bid-strategy": {
|
|
34352
34391
|
type: "string",
|
|
@@ -34357,6 +34396,10 @@ var SHARED_ARGS = {
|
|
|
34357
34396
|
type: "string",
|
|
34358
34397
|
description: "Query string added to this ad group's landing pages, e.g. utm_content={ad_group_id} \u2014 none clears"
|
|
34359
34398
|
},
|
|
34399
|
+
"audience-bids": {
|
|
34400
|
+
type: "string",
|
|
34401
|
+
description: "Raise or lower the fixed bid for people in an audience: audience=multiplier pairs, 0.1 to 10, e.g. caud_123=1.5,caud_456=0.8. Audiences of ~25,000 people only; not in the EEA or Switzerland. On update it replaces them; none clears"
|
|
34402
|
+
},
|
|
34360
34403
|
"product-filters": {
|
|
34361
34404
|
type: "string",
|
|
34362
34405
|
description: "Catalog campaigns only: which products it shows \u2014 e.g. brand in Acme; price lte 5000 (preview with `catalogs products`). On update it replaces the set; none shows the whole catalog"
|
|
@@ -34372,6 +34415,32 @@ var UPDATE_ARGS2 = {
|
|
|
34372
34415
|
id: { type: "positional", description: "Ad group id (adgrp_\u2026) or a staged chatgpt_temp_ ref", required: true },
|
|
34373
34416
|
...SHARED_ARGS
|
|
34374
34417
|
};
|
|
34418
|
+
function contextHintsArg(value) {
|
|
34419
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
34420
|
+
return void 0;
|
|
34421
|
+
}
|
|
34422
|
+
if (value.trim().toLowerCase() === "none") {
|
|
34423
|
+
return [];
|
|
34424
|
+
}
|
|
34425
|
+
const separator = value.includes("|") ? "|" : ",";
|
|
34426
|
+
return value.split(separator).map((hint) => hint.trim()).filter(Boolean);
|
|
34427
|
+
}
|
|
34428
|
+
function audienceBidsArg(value) {
|
|
34429
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
34430
|
+
return void 0;
|
|
34431
|
+
}
|
|
34432
|
+
if (value.trim().toLowerCase() === "none") {
|
|
34433
|
+
return [];
|
|
34434
|
+
}
|
|
34435
|
+
return value.split(",").map((pair) => pair.trim()).filter(Boolean).map((pair) => {
|
|
34436
|
+
const [audienceId = "", multiplier = ""] = pair.split("=").map((part) => part.trim());
|
|
34437
|
+
const times = Number(multiplier.replace(",", "."));
|
|
34438
|
+
if (!audienceId || !Number.isFinite(times)) {
|
|
34439
|
+
failWriteValidation(`"${pair}" is not an audience bid \u2014 write audience=multiplier, e.g. caud_123=1.5`);
|
|
34440
|
+
}
|
|
34441
|
+
return { audienceId, multiplierMicros: Math.round(times * 1e6) };
|
|
34442
|
+
});
|
|
34443
|
+
}
|
|
34375
34444
|
function productSetArg(value) {
|
|
34376
34445
|
const filters = productFiltersArg(value);
|
|
34377
34446
|
return filters === void 0 ? void 0 : { filters };
|
|
@@ -34380,11 +34449,12 @@ function sharedPayload(args8) {
|
|
|
34380
34449
|
return {
|
|
34381
34450
|
name: args8.name,
|
|
34382
34451
|
description: args8.description,
|
|
34383
|
-
contextHints:
|
|
34452
|
+
contextHints: contextHintsArg(args8["context-hints"]),
|
|
34384
34453
|
bidStrategy: lowerArg(args8["bid-strategy"]),
|
|
34385
34454
|
maxBidMicros: microsFromArg(args8["max-bid"], "--max-bid"),
|
|
34386
34455
|
trackingTemplate: clearableArg(args8["tracking-template"]),
|
|
34387
34456
|
productSet: productSetArg(args8["product-filters"]),
|
|
34457
|
+
audienceBidMultipliers: audienceBidsArg(args8["audience-bids"]),
|
|
34388
34458
|
status: lowerArg(args8.status)
|
|
34389
34459
|
};
|
|
34390
34460
|
}
|
|
@@ -34408,7 +34478,7 @@ Examples:
|
|
|
34408
34478
|
args: CREATE_ARGS,
|
|
34409
34479
|
run: async ({ args: args8 }) => {
|
|
34410
34480
|
await stageChatgptOp(adGroupCreateOp(args8), REFERENCE2, (staged) => [
|
|
34411
|
-
|
|
34481
|
+
adGroupNextHint(staged.ref, args8["product-filters"] !== void 0)
|
|
34412
34482
|
]);
|
|
34413
34483
|
}
|
|
34414
34484
|
});
|
|
@@ -34437,6 +34507,10 @@ Examples:
|
|
|
34437
34507
|
var adGroupsPauseCommand = statusCommand2("adGroup", "pause", REFERENCE2);
|
|
34438
34508
|
var adGroupsResumeCommand = statusCommand2("adGroup", "resume", REFERENCE2);
|
|
34439
34509
|
var adGroupsArchiveCommand = statusCommand2("adGroup", "archive", REFERENCE2);
|
|
34510
|
+
function adGroupNextHint(ref, productFilters) {
|
|
34511
|
+
const productAd = `baker ads chatgpt ads create-product --ad-group-id ${ref} --name "\u2026"`;
|
|
34512
|
+
return productFilters ? `Next, give it its product ad: ${productAd}` : `Next, give it a card: baker ads chatgpt ads create --ad-group-id ${ref} --name "\u2026" --title "\u2026" --body "\u2026" --target-url https://\u2026 --image-url https://\u2026 \u2014 under a catalog campaign, its product ad instead: ${productAd}`;
|
|
34513
|
+
}
|
|
34440
34514
|
|
|
34441
34515
|
// src/commands/ads/chatgpt/ad-groups.ts
|
|
34442
34516
|
var args = {
|
|
@@ -34707,7 +34781,7 @@ function sha256(value) {
|
|
|
34707
34781
|
}
|
|
34708
34782
|
function normalizedEmail(value) {
|
|
34709
34783
|
const email = value.trim().toLowerCase();
|
|
34710
|
-
return /^[^@\s]+@[^@\s]+$/.test(email) ? email : void 0;
|
|
34784
|
+
return /^[^@\s;,|]+@[^@\s;,|]+\.[^@\s;,|]+$/.test(email) ? email : void 0;
|
|
34711
34785
|
}
|
|
34712
34786
|
function normalizedPhone(value, defaultCountry) {
|
|
34713
34787
|
const country = defaultCountry && isSupportedCountry(defaultCountry) ? defaultCountry : void 0;
|
|
@@ -34728,13 +34802,22 @@ function hashedMembers(input) {
|
|
|
34728
34802
|
}
|
|
34729
34803
|
return { emailHashes: [...emailHashes], phoneHashes: [...phoneHashes], rejected };
|
|
34730
34804
|
}
|
|
34731
|
-
|
|
34732
|
-
|
|
34805
|
+
function headerWords(cell3) {
|
|
34806
|
+
return cell3.normalize("NFD").replace(new RegExp("\\p{Diacritic}", "gu"), "").toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
34807
|
+
}
|
|
34808
|
+
var EMAIL_HEADER = /\b(e ?mail|correo|mail)\b/;
|
|
34809
|
+
var PHONE_HEADER = /\b(phone|telefono|movil|mobile|tel|celular)\b/;
|
|
34733
34810
|
function membersFromFile(content) {
|
|
34734
|
-
const rows = parse(content, {
|
|
34735
|
-
|
|
34736
|
-
|
|
34737
|
-
|
|
34811
|
+
const rows = parse(content, {
|
|
34812
|
+
bom: true,
|
|
34813
|
+
skip_empty_lines: true,
|
|
34814
|
+
relax_column_count: true,
|
|
34815
|
+
trim: true,
|
|
34816
|
+
delimiter: [",", ";", " "]
|
|
34817
|
+
});
|
|
34818
|
+
const header = (rows[0] ?? []).map(headerWords);
|
|
34819
|
+
const emailColumn = header.findIndex((cell3) => EMAIL_HEADER.test(cell3));
|
|
34820
|
+
const phoneColumn = header.findIndex((cell3) => !EMAIL_HEADER.test(cell3) && PHONE_HEADER.test(cell3));
|
|
34738
34821
|
if (emailColumn >= 0 || phoneColumn >= 0) {
|
|
34739
34822
|
const cells = (column) => column < 0 ? [] : rows.slice(1).flatMap((row) => row[column] ? [row[column]] : []);
|
|
34740
34823
|
return { emails: cells(emailColumn), phones: cells(phoneColumn) };
|
|
@@ -34756,21 +34839,23 @@ var MEMBER_ARGS = {
|
|
|
34756
34839
|
};
|
|
34757
34840
|
function membersFromArgs(args8, readFile34 = (path48) => readFileSync2(path48, "utf8")) {
|
|
34758
34841
|
const fromFile = typeof args8.file === "string" && args8.file ? membersFromFile(readFile34(args8.file)) : { emails: [], phones: [] };
|
|
34842
|
+
const given = [...csvArg(args8.emails) ?? [], ...fromFile.emails];
|
|
34843
|
+
const givenPhones = [...csvArg(args8.phones) ?? [], ...fromFile.phones];
|
|
34759
34844
|
const members = hashedMembers({
|
|
34760
|
-
emails:
|
|
34761
|
-
phones:
|
|
34845
|
+
emails: given,
|
|
34846
|
+
phones: givenPhones,
|
|
34762
34847
|
defaultCountry: typeof args8.country === "string" ? args8.country.toUpperCase() : void 0
|
|
34763
34848
|
});
|
|
34764
34849
|
const count2 = members.emailHashes.length + members.phoneHashes.length;
|
|
34765
|
-
|
|
34766
|
-
|
|
34767
|
-
}
|
|
34850
|
+
const offered = given.length + givenPhones.length + (typeof args8.file === "string" && args8.file ? 1 : 0);
|
|
34851
|
+
const refusal = count2 > CHATGPT_MAX_STAGED_MEMBERS ? `${count2} members \u2014 at most ${CHATGPT_MAX_STAGED_MEMBERS} per change; split the file` : count2 === 0 && offered > 0 ? "none of the values was an email or a valid phone \u2014 name the columns email and phone, and give phones a +country code or --country" : void 0;
|
|
34768
34852
|
return {
|
|
34769
34853
|
payload: {
|
|
34770
34854
|
...members.emailHashes.length > 0 ? { emailHashes: members.emailHashes } : {},
|
|
34771
34855
|
...members.phoneHashes.length > 0 ? { phoneHashes: members.phoneHashes } : {}
|
|
34772
34856
|
},
|
|
34773
|
-
rejected: members.rejected.length
|
|
34857
|
+
rejected: members.rejected.length,
|
|
34858
|
+
...refusal ? { refusal } : {}
|
|
34774
34859
|
};
|
|
34775
34860
|
}
|
|
34776
34861
|
function rejectedHint(rejected) {
|
|
@@ -34825,7 +34910,10 @@ Examples:
|
|
|
34825
34910
|
},
|
|
34826
34911
|
args: CREATE_ARGS3,
|
|
34827
34912
|
run: async ({ args: args8 }) => {
|
|
34828
|
-
const { payload, rejected } = membersFromArgs(args8);
|
|
34913
|
+
const { payload, rejected, refusal } = membersFromArgs(args8);
|
|
34914
|
+
if (refusal) {
|
|
34915
|
+
failWriteValidation(refusal);
|
|
34916
|
+
}
|
|
34829
34917
|
await stageChatgptOp(
|
|
34830
34918
|
{
|
|
34831
34919
|
kind: "audience.create",
|
|
@@ -34859,7 +34947,10 @@ Example:
|
|
|
34859
34947
|
},
|
|
34860
34948
|
args: args8,
|
|
34861
34949
|
run: async ({ args: parsed }) => {
|
|
34862
|
-
const { payload, rejected } = membersFromArgs(parsed);
|
|
34950
|
+
const { payload, rejected, refusal } = membersFromArgs(parsed);
|
|
34951
|
+
if (refusal) {
|
|
34952
|
+
failWriteValidation(refusal);
|
|
34953
|
+
}
|
|
34863
34954
|
if (!payload.emailHashes && !payload.phoneHashes) {
|
|
34864
34955
|
failWriteValidation("name at least one email or phone with --emails, --phones or --file");
|
|
34865
34956
|
}
|
|
@@ -35025,7 +35116,8 @@ Examples:
|
|
|
35025
35116
|
args: CREATE_ARGS4,
|
|
35026
35117
|
run: async ({ args: args8 }) => {
|
|
35027
35118
|
await stageChatgptOp(campaignCreateOp(args8), REFERENCE5, (staged) => [
|
|
35028
|
-
`Next, give it an ad group: baker ads chatgpt ad-groups create --campaign-id ${staged.ref} --name "\u2026" --context-hints "\u2026" --max-bid 2.50
|
|
35119
|
+
`Next, give it an ad group: baker ads chatgpt ad-groups create --campaign-id ${staged.ref} --name "\u2026" --context-hints "\u2026" --max-bid 2.50`,
|
|
35120
|
+
"Check this summary against everything the user asked for \u2014 countries, places to leave out, budget, dates \u2014 and stage what is missing before saying it is ready."
|
|
35029
35121
|
]);
|
|
35030
35122
|
}
|
|
35031
35123
|
});
|