@koda-sl/baker-cli 0.380.0-dev.59908a419 → 0.380.0-dev.d26778d3f
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 +44 -4
- package/dist/cli.js +1708 -508
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -133,7 +133,7 @@ import {
|
|
|
133
133
|
} from "./chunk-7YNOGIWQ.js";
|
|
134
134
|
|
|
135
135
|
// src/cli.ts
|
|
136
|
-
import { defineCommand as
|
|
136
|
+
import { defineCommand as defineCommand255, runMain } from "citty";
|
|
137
137
|
|
|
138
138
|
// src/cache-flag.ts
|
|
139
139
|
var NO_CACHE_ARG = {
|
|
@@ -1209,8 +1209,8 @@ var campaignUpdateSchema = z3.object({
|
|
|
1209
1209
|
}
|
|
1210
1210
|
validateCampaignBudgets(p, ctx, { requireBudget: false });
|
|
1211
1211
|
});
|
|
1212
|
-
function trackingParamsLevel(
|
|
1213
|
-
return SPONSORED_ACCOUNT_URN_REGEX.test(
|
|
1212
|
+
function trackingParamsLevel(target4) {
|
|
1213
|
+
return SPONSORED_ACCOUNT_URN_REGEX.test(target4) ? "account" : "campaign";
|
|
1214
1214
|
}
|
|
1215
1215
|
function bareLinkedinUrnId(urn) {
|
|
1216
1216
|
return urn.split(":").pop() ?? urn;
|
|
@@ -4329,7 +4329,8 @@ var CAPABILITY_SURFACES = [
|
|
|
4329
4329
|
"x-ads",
|
|
4330
4330
|
"tag-manager",
|
|
4331
4331
|
"ga4",
|
|
4332
|
-
"gsc"
|
|
4332
|
+
"gsc",
|
|
4333
|
+
"shopify"
|
|
4333
4334
|
];
|
|
4334
4335
|
var CAPABILITY_SURFACE_SPECS = {
|
|
4335
4336
|
"google-ads": {
|
|
@@ -4412,6 +4413,26 @@ var CAPABILITY_SURFACE_SPECS = {
|
|
|
4412
4413
|
writePath: "read-only",
|
|
4413
4414
|
writeScopes: ["https://www.googleapis.com/auth/webmasters"],
|
|
4414
4415
|
commands: "baker gsc"
|
|
4416
|
+
},
|
|
4417
|
+
shopify: {
|
|
4418
|
+
id: "shopify",
|
|
4419
|
+
label: "Shopify store",
|
|
4420
|
+
provider: "shopify",
|
|
4421
|
+
resourceNoun: "store",
|
|
4422
|
+
// Staged during the chat and applied to the real store when it completes,
|
|
4423
|
+
// every time; each applied change can be put back by another publish
|
|
4424
|
+
// (`baker shopify undo`). The write permissions are optional scopes the
|
|
4425
|
+
// store grants when a change first needs one, so `scopeBlockers` is the
|
|
4426
|
+
// per-company signal.
|
|
4427
|
+
writePath: "staged-immediate",
|
|
4428
|
+
writeScopes: [
|
|
4429
|
+
"write_products",
|
|
4430
|
+
"write_publications",
|
|
4431
|
+
"write_discounts",
|
|
4432
|
+
"write_online_store_navigation",
|
|
4433
|
+
"write_marketing_events"
|
|
4434
|
+
],
|
|
4435
|
+
commands: "baker shopify"
|
|
4415
4436
|
}
|
|
4416
4437
|
};
|
|
4417
4438
|
|
|
@@ -4530,6 +4551,8 @@ var chatChangeTypeSchema = z13.enum([
|
|
|
4530
4551
|
"x-ads",
|
|
4531
4552
|
"tag-manager",
|
|
4532
4553
|
"ga4",
|
|
4554
|
+
// Changes to the company's Shopify store (S9). Staged, applied at Publish.
|
|
4555
|
+
"shopify",
|
|
4533
4556
|
// A recipe the company added to their own marketplace, staged like any other
|
|
4534
4557
|
// Session effect — see convex/companyTemplates/mutations.ts.
|
|
4535
4558
|
"recipe",
|
|
@@ -4750,6 +4773,7 @@ var chatEffectsSchema = z13.object({
|
|
|
4750
4773
|
creatives: z13.array(creativeEffectSchema),
|
|
4751
4774
|
tagManager: z13.array(configEffectSchema),
|
|
4752
4775
|
ga4: z13.array(configEffectSchema),
|
|
4776
|
+
shopify: z13.array(configEffectSchema),
|
|
4753
4777
|
funnel: z13.array(funnelEffectSchema),
|
|
4754
4778
|
conversions: z13.array(settingEffectSchema),
|
|
4755
4779
|
conversionSends: z13.array(settingEffectSchema),
|
|
@@ -6970,7 +6994,6 @@ var STORE_EVENTS = {
|
|
|
6970
6994
|
product_out_of_stock: {
|
|
6971
6995
|
label: "A product runs out of stock",
|
|
6972
6996
|
sentence: "When a product in your Shopify store runs out of stock",
|
|
6973
|
-
description: "One or more of its options can no longer be bought; whole_product says whether nothing at all can be.",
|
|
6974
6997
|
payload: [
|
|
6975
6998
|
"title",
|
|
6976
6999
|
"handle",
|
|
@@ -6981,13 +7004,11 @@ var STORE_EVENTS = {
|
|
|
6981
7004
|
"promoted_by",
|
|
6982
7005
|
"promotions_checked",
|
|
6983
7006
|
...PRODUCT_FIELDS.slice(2)
|
|
6984
|
-
]
|
|
6985
|
-
namesProduct: true
|
|
7007
|
+
]
|
|
6986
7008
|
},
|
|
6987
7009
|
product_back_in_stock: {
|
|
6988
7010
|
label: "A product is back in stock",
|
|
6989
7011
|
sentence: "When a product in your Shopify store is back in stock",
|
|
6990
|
-
description: "Options that ran out can be bought again, or ads were paused for it after it came back.",
|
|
6991
7012
|
payload: [
|
|
6992
7013
|
"title",
|
|
6993
7014
|
"handle",
|
|
@@ -6998,20 +7019,16 @@ var STORE_EVENTS = {
|
|
|
6998
7019
|
"reason",
|
|
6999
7020
|
"promoted_by",
|
|
7000
7021
|
...PRODUCT_FIELDS.slice(2)
|
|
7001
|
-
]
|
|
7002
|
-
namesProduct: true
|
|
7022
|
+
]
|
|
7003
7023
|
},
|
|
7004
7024
|
product_created: {
|
|
7005
7025
|
label: "A new product is added",
|
|
7006
7026
|
sentence: "When a new product is added to your Shopify store",
|
|
7007
|
-
|
|
7008
|
-
payload: [...PRODUCT_FIELDS],
|
|
7009
|
-
namesProduct: true
|
|
7027
|
+
payload: [...PRODUCT_FIELDS]
|
|
7010
7028
|
},
|
|
7011
7029
|
product_updated: {
|
|
7012
7030
|
label: "A product is changed",
|
|
7013
7031
|
sentence: "When a product in your Shopify store is changed",
|
|
7014
|
-
description: "Its price, title, status, publication, handle, tags, type, vendor or description changed; stock changes and changes Baker made do not count.",
|
|
7015
7032
|
payload: [
|
|
7016
7033
|
"title",
|
|
7017
7034
|
"handle",
|
|
@@ -7022,41 +7039,33 @@ var STORE_EVENTS = {
|
|
|
7022
7039
|
"before_published",
|
|
7023
7040
|
"price_changes",
|
|
7024
7041
|
...PRODUCT_FIELDS.slice(2)
|
|
7025
|
-
]
|
|
7026
|
-
namesProduct: true
|
|
7042
|
+
]
|
|
7027
7043
|
},
|
|
7028
7044
|
collection_updated: {
|
|
7029
7045
|
label: "A collection changes",
|
|
7030
7046
|
sentence: "When a collection in your Shopify store changes",
|
|
7031
|
-
|
|
7032
|
-
payload: ["title", "collection", "changed", "product_count", "before_product_count", "published", "store"],
|
|
7033
|
-
namesProduct: false
|
|
7047
|
+
payload: ["title", "collection", "changed", "product_count", "before_product_count", "published", "store"]
|
|
7034
7048
|
},
|
|
7035
7049
|
purchase: {
|
|
7036
7050
|
label: "An order is paid",
|
|
7037
7051
|
sentence: "When an order is paid",
|
|
7038
|
-
description: "The store's sale; value is the order's total in the store's currency.",
|
|
7039
7052
|
payload: ["order_name", "ordered_at", "shopify_source", "visitor_from", "campaign_from", "store"],
|
|
7040
|
-
|
|
7053
|
+
alsoTheSite: true
|
|
7041
7054
|
},
|
|
7042
7055
|
refund: {
|
|
7043
7056
|
label: "Money is refunded on an order",
|
|
7044
7057
|
sentence: "When money is refunded on an order",
|
|
7045
|
-
description: "Money given back on an order; value is the amount refunded.",
|
|
7046
7058
|
payload: ["order_name", "store"],
|
|
7047
|
-
|
|
7059
|
+
alsoTheSite: true
|
|
7048
7060
|
},
|
|
7049
7061
|
customer_created: {
|
|
7050
7062
|
label: "A new customer signs up",
|
|
7051
7063
|
sentence: "When a new customer account is created in your Shopify store",
|
|
7052
|
-
|
|
7053
|
-
payload: ["customer", "country", "accepts_email", "orders", "tags", "account_state", "store"],
|
|
7054
|
-
namesProduct: false
|
|
7064
|
+
payload: ["customer", "country", "accepts_email", "orders", "tags", "account_state", "store"]
|
|
7055
7065
|
},
|
|
7056
7066
|
checkout_abandoned: {
|
|
7057
7067
|
label: "A checkout is abandoned",
|
|
7058
7068
|
sentence: "When a shopper leaves a checkout in your Shopify store without buying",
|
|
7059
|
-
description: "A checkout with contact details was not completed after an hour.",
|
|
7060
7069
|
payload: [
|
|
7061
7070
|
"total",
|
|
7062
7071
|
"currency",
|
|
@@ -7069,13 +7078,11 @@ var STORE_EVENTS = {
|
|
|
7069
7078
|
"started_at",
|
|
7070
7079
|
"last_activity_at",
|
|
7071
7080
|
"store"
|
|
7072
|
-
]
|
|
7073
|
-
namesProduct: false
|
|
7081
|
+
]
|
|
7074
7082
|
},
|
|
7075
7083
|
sales_drop: {
|
|
7076
7084
|
label: "Sales drop",
|
|
7077
7085
|
sentence: "When your Shopify store's sales drop well below usual",
|
|
7078
|
-
description: "The last 6 hours brought far fewer orders than the same hours usually do.",
|
|
7079
7086
|
payload: [
|
|
7080
7087
|
"window_hours",
|
|
7081
7088
|
"window_start",
|
|
@@ -7088,8 +7095,7 @@ var STORE_EVENTS = {
|
|
|
7088
7095
|
"drop_percent",
|
|
7089
7096
|
"baseline_days",
|
|
7090
7097
|
"store"
|
|
7091
|
-
]
|
|
7092
|
-
namesProduct: false
|
|
7098
|
+
]
|
|
7093
7099
|
}
|
|
7094
7100
|
};
|
|
7095
7101
|
var STORE_EVENT_NAMES = Object.keys(STORE_EVENTS);
|
|
@@ -8435,8 +8441,8 @@ var videosDeleteResponseSchema = z29.object({ ok: z29.literal(true) });
|
|
|
8435
8441
|
|
|
8436
8442
|
// src/commands/actions/tagError.ts
|
|
8437
8443
|
var UNKNOWN_TAG_RE = /Unknown action tag\(s\): ([^.]+)\. Valid tags: ([^.]+)\./;
|
|
8438
|
-
function splitSlugs(
|
|
8439
|
-
return
|
|
8444
|
+
function splitSlugs(list3) {
|
|
8445
|
+
return list3.split(",").map((slug) => slug.trim()).filter((slug) => slug.length > 0);
|
|
8440
8446
|
}
|
|
8441
8447
|
function actionTagFix(message) {
|
|
8442
8448
|
const match = UNKNOWN_TAG_RE.exec(message);
|
|
@@ -8725,6 +8731,13 @@ function buildCreateHints({
|
|
|
8725
8731
|
draftCreateCount
|
|
8726
8732
|
}) {
|
|
8727
8733
|
const hints2 = [];
|
|
8734
|
+
const expanded = shellExpandedIn(`${name}
|
|
8735
|
+
${description}`);
|
|
8736
|
+
if (expanded) {
|
|
8737
|
+
hints2.push(
|
|
8738
|
+
`The text says \u201C${expanded}\u201D: the shell replaced a $ amount (like $0) inside double quotes before Baker saw it. Fix it now: baker actions update ${tempId} --description '<the text, with the amounts as you read them>' (and --name '\u2026' if the name has it) \u2014 single quotes keep $ as written.`
|
|
8739
|
+
);
|
|
8740
|
+
}
|
|
8728
8741
|
const advisory = advisoryHint(name, description);
|
|
8729
8742
|
if (advisory) {
|
|
8730
8743
|
hints2.push(
|
|
@@ -8756,6 +8769,9 @@ function buildCreateHints({
|
|
|
8756
8769
|
}
|
|
8757
8770
|
return hints2;
|
|
8758
8771
|
}
|
|
8772
|
+
function shellExpandedIn(text2) {
|
|
8773
|
+
return /(?:^|[\s(])((?:\/usr)?\/bin\/(?:ba|z|da|k)?sh|-?(?:ba|z|da|k)sh)\b/.exec(text2)?.[1] ?? null;
|
|
8774
|
+
}
|
|
8759
8775
|
function advisoryHint(name, description) {
|
|
8760
8776
|
if (looksScheduled(name, description)) {
|
|
8761
8777
|
return { kind: "scheduled", hint: SCHEDULED_HINT };
|
|
@@ -9948,7 +9964,7 @@ import { defineCommand as defineCommand19 } from "citty";
|
|
|
9948
9964
|
function listed(resources) {
|
|
9949
9965
|
return resources.map((resource) => resource.label ? `${resource.id} (${resource.label})` : resource.id).join("; ");
|
|
9950
9966
|
}
|
|
9951
|
-
function connectedResourceHints({ plural:
|
|
9967
|
+
function connectedResourceHints({ plural: plural3, singular, flag: flag3, resources }) {
|
|
9952
9968
|
if (resources.length === 0) {
|
|
9953
9969
|
return [];
|
|
9954
9970
|
}
|
|
@@ -9956,7 +9972,7 @@ function connectedResourceHints({ plural: plural2, singular, flag: flag3, resour
|
|
|
9956
9972
|
return [`This company connected one ${singular}: ${listed(resources)}. Commands use it unless you pass ${flag3}.`];
|
|
9957
9973
|
}
|
|
9958
9974
|
return [
|
|
9959
|
-
`This company connected ${resources.length} ${
|
|
9975
|
+
`This company connected ${resources.length} ${plural3}: ${listed(resources)}. Each command works on one, so pass ${flag3} \u2014 nothing is picked for you. A question about the whole business covers all ${resources.length}: answering from one and reporting it as the total is wrong.`
|
|
9960
9976
|
];
|
|
9961
9977
|
}
|
|
9962
9978
|
|
|
@@ -11591,8 +11607,8 @@ function capabilityFix(surface) {
|
|
|
11591
11607
|
// src/commands/ads/boolean-word-positional.ts
|
|
11592
11608
|
var BOOLEAN_WORD = /^(true|false)$/i;
|
|
11593
11609
|
function booleanWordPositionalError(args5, entity) {
|
|
11594
|
-
const
|
|
11595
|
-
const word =
|
|
11610
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
11611
|
+
const word = positionals2.find((value2) => typeof value2 === "string" && BOOLEAN_WORD.test(value2));
|
|
11596
11612
|
if (word === void 0) {
|
|
11597
11613
|
return void 0;
|
|
11598
11614
|
}
|
|
@@ -11926,7 +11942,7 @@ function words(headline) {
|
|
|
11926
11942
|
return headline.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter(Boolean);
|
|
11927
11943
|
}
|
|
11928
11944
|
function canonical(word) {
|
|
11929
|
-
for (const [i,
|
|
11945
|
+
for (const [i, group2] of CYCLED_VERBS.entries()) if (group2.includes(word)) return `group:${i}`;
|
|
11930
11946
|
return word;
|
|
11931
11947
|
}
|
|
11932
11948
|
function overlap(a, b) {
|
|
@@ -12201,11 +12217,11 @@ function requireTarget(args5, entity) {
|
|
|
12201
12217
|
failWriteValidation(booleanWord);
|
|
12202
12218
|
}
|
|
12203
12219
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
12204
|
-
const
|
|
12205
|
-
if (typeof
|
|
12220
|
+
const target4 = args5.id ?? args5.target ?? args5.ref ?? positional;
|
|
12221
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
12206
12222
|
failWriteValidation(`pass the ${entity} resource name or id as the positional argument`);
|
|
12207
12223
|
}
|
|
12208
|
-
return
|
|
12224
|
+
return target4;
|
|
12209
12225
|
}
|
|
12210
12226
|
function requireStringFlag(value, flag3) {
|
|
12211
12227
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -12413,11 +12429,11 @@ async function stageGoogleOps(rawOps, hints2) {
|
|
|
12413
12429
|
handleGoogleError(err);
|
|
12414
12430
|
}
|
|
12415
12431
|
}
|
|
12416
|
-
async function stageUpdate(kind, customerId,
|
|
12417
|
-
await stageGoogleOp({ kind, customerId, target:
|
|
12432
|
+
async function stageUpdate(kind, customerId, target4, payload, hints2) {
|
|
12433
|
+
await stageGoogleOp({ kind, customerId, target: target4, payload }, hints2);
|
|
12418
12434
|
}
|
|
12419
|
-
async function stageTarget(kind, customerId,
|
|
12420
|
-
await stageGoogleOp({ kind, customerId, target:
|
|
12435
|
+
async function stageTarget(kind, customerId, target4, hints2) {
|
|
12436
|
+
await stageGoogleOp({ kind, customerId, target: target4 }, hints2);
|
|
12421
12437
|
}
|
|
12422
12438
|
async function draftAction(path49, body, chat) {
|
|
12423
12439
|
try {
|
|
@@ -12596,9 +12612,9 @@ var DATAFORSEO_LANGUAGES = [
|
|
|
12596
12612
|
{ code: "da", name: "Danish" },
|
|
12597
12613
|
{ code: "fi", name: "Finnish" }
|
|
12598
12614
|
];
|
|
12599
|
-
function toRecord(
|
|
12615
|
+
function toRecord(list3) {
|
|
12600
12616
|
const map = {};
|
|
12601
|
-
for (const item of
|
|
12617
|
+
for (const item of list3) {
|
|
12602
12618
|
const key = item.id ?? item.code;
|
|
12603
12619
|
if (key) map[key] = item.name;
|
|
12604
12620
|
}
|
|
@@ -13974,9 +13990,9 @@ function servingScopeWarnings(args5, finalQuery) {
|
|
|
13974
13990
|
}
|
|
13975
13991
|
function parseSelectedFields(gaql) {
|
|
13976
13992
|
const match = gaql.match(/\bSELECT\b([\s\S]*?)\bFROM\b/i);
|
|
13977
|
-
const
|
|
13978
|
-
if (!
|
|
13979
|
-
return
|
|
13993
|
+
const list3 = match?.[1];
|
|
13994
|
+
if (!list3) return [];
|
|
13995
|
+
return list3.split(",").map((field) => field.trim()).filter((field) => /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z0-9_]+)*$/.test(field));
|
|
13980
13996
|
}
|
|
13981
13997
|
function foldObservedFields(rows, observed) {
|
|
13982
13998
|
for (const row of rows) {
|
|
@@ -18075,19 +18091,19 @@ var CSV_SEPARATORS = /* @__PURE__ */ new Set([",", ";", " "]);
|
|
|
18075
18091
|
function splitCsvLine(line) {
|
|
18076
18092
|
const fields = [];
|
|
18077
18093
|
let current = "";
|
|
18078
|
-
let
|
|
18094
|
+
let quoted2 = false;
|
|
18079
18095
|
for (let i = 0; i < line.length; i++) {
|
|
18080
18096
|
const char = line[i];
|
|
18081
|
-
if (
|
|
18097
|
+
if (quoted2 && char !== '"') {
|
|
18082
18098
|
current += char;
|
|
18083
|
-
} else if (
|
|
18084
|
-
|
|
18085
|
-
if (
|
|
18099
|
+
} else if (quoted2) {
|
|
18100
|
+
quoted2 = line[i + 1] === '"';
|
|
18101
|
+
if (quoted2) {
|
|
18086
18102
|
current += '"';
|
|
18087
18103
|
i += 1;
|
|
18088
18104
|
}
|
|
18089
18105
|
} else if (char === '"') {
|
|
18090
|
-
|
|
18106
|
+
quoted2 = true;
|
|
18091
18107
|
} else if (CSV_SEPARATORS.has(char ?? "")) {
|
|
18092
18108
|
fields.push(current);
|
|
18093
18109
|
current = "";
|
|
@@ -18431,13 +18447,13 @@ var budgetsCommand = defineCommand31({
|
|
|
18431
18447
|
},
|
|
18432
18448
|
run: async ({ args: args5 }) => {
|
|
18433
18449
|
const customerId = requireCustomerId(args5);
|
|
18434
|
-
const
|
|
18450
|
+
const target4 = requireTarget(args5, "budget");
|
|
18435
18451
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
18436
18452
|
name: args5.name,
|
|
18437
18453
|
amountMicros: microsFlag(args5.amount, "--amount"),
|
|
18438
18454
|
deliveryMethod: args5.delivery
|
|
18439
18455
|
});
|
|
18440
|
-
await stageUpdate("google.budget.update", customerId,
|
|
18456
|
+
await stageUpdate("google.budget.update", customerId, target4, payload, BUDGET_DEMAND_HINTS);
|
|
18441
18457
|
}
|
|
18442
18458
|
})
|
|
18443
18459
|
}
|
|
@@ -18753,7 +18769,7 @@ var campaignsCommand = defineCommand31({
|
|
|
18753
18769
|
if (level !== "campaign") {
|
|
18754
18770
|
failWriteValidation("--level must be campaign or account");
|
|
18755
18771
|
}
|
|
18756
|
-
const
|
|
18772
|
+
const target4 = requireTarget(args5, "campaign");
|
|
18757
18773
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
18758
18774
|
name: args5.name,
|
|
18759
18775
|
budget: args5["budget-ref"],
|
|
@@ -18766,7 +18782,7 @@ var campaignsCommand = defineCommand31({
|
|
|
18766
18782
|
euPoliticalAds: args5["eu-political-ads"],
|
|
18767
18783
|
status: args5.status
|
|
18768
18784
|
});
|
|
18769
|
-
await stageUpdate("google.campaign.update", customerId,
|
|
18785
|
+
await stageUpdate("google.campaign.update", customerId, target4, payload);
|
|
18770
18786
|
}
|
|
18771
18787
|
}),
|
|
18772
18788
|
pause: statusCommand2("google.campaign.pause", "campaign"),
|
|
@@ -18836,13 +18852,13 @@ var adGroupsCommand = defineCommand31({
|
|
|
18836
18852
|
},
|
|
18837
18853
|
run: async ({ args: args5 }) => {
|
|
18838
18854
|
const customerId = requireCustomerId(args5);
|
|
18839
|
-
const
|
|
18855
|
+
const target4 = requireTarget(args5, "ad group");
|
|
18840
18856
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
18841
18857
|
name: args5.name,
|
|
18842
18858
|
cpcBidMicros: microsFlag(args5["cpc-bid"], "--cpc-bid"),
|
|
18843
18859
|
status: args5.status
|
|
18844
18860
|
});
|
|
18845
|
-
await stageUpdate("google.adGroup.update", customerId,
|
|
18861
|
+
await stageUpdate("google.adGroup.update", customerId, target4, payload);
|
|
18846
18862
|
}
|
|
18847
18863
|
}),
|
|
18848
18864
|
pause: statusCommand2("google.adGroup.pause", "ad group"),
|
|
@@ -18870,11 +18886,11 @@ function keywordFinalUrlHints(finalUrl, count2) {
|
|
|
18870
18886
|
}
|
|
18871
18887
|
function keywordUpdateFinalUrls(args5) {
|
|
18872
18888
|
const finalUrl = args5["final-url"];
|
|
18873
|
-
const
|
|
18889
|
+
const clear2 = args5["clear-final-url"] === true;
|
|
18874
18890
|
if (typeof finalUrl !== "string" || finalUrl.length === 0) {
|
|
18875
|
-
return
|
|
18891
|
+
return clear2 ? [] : void 0;
|
|
18876
18892
|
}
|
|
18877
|
-
if (
|
|
18893
|
+
if (clear2) {
|
|
18878
18894
|
failWriteValidation(
|
|
18879
18895
|
"--clear-final-url sends the keyword back to the ad's landing page \u2014 pass it OR --final-url, not both"
|
|
18880
18896
|
);
|
|
@@ -19490,13 +19506,13 @@ var assetGroupsCommand = defineCommand31({
|
|
|
19490
19506
|
},
|
|
19491
19507
|
run: async ({ args: args5 }) => {
|
|
19492
19508
|
const customerId = requireCustomerId(args5);
|
|
19493
|
-
const
|
|
19509
|
+
const target4 = requireTarget(args5, "asset group");
|
|
19494
19510
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
19495
19511
|
name: args5.name,
|
|
19496
19512
|
finalUrls: listFlag(args5["final-urls"]),
|
|
19497
19513
|
status: args5.status
|
|
19498
19514
|
});
|
|
19499
|
-
await stageUpdate("google.assetGroup.update", customerId,
|
|
19515
|
+
await stageUpdate("google.assetGroup.update", customerId, target4, payload);
|
|
19500
19516
|
}
|
|
19501
19517
|
}),
|
|
19502
19518
|
attach: defineCommand31({
|
|
@@ -19578,7 +19594,7 @@ var assetsUpdateCommand = defineCommand31({
|
|
|
19578
19594
|
},
|
|
19579
19595
|
run: async ({ args: args5 }) => {
|
|
19580
19596
|
const customerId = requireCustomerId(args5);
|
|
19581
|
-
const
|
|
19597
|
+
const target4 = requireTarget(args5, "asset");
|
|
19582
19598
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
19583
19599
|
name: args5.name,
|
|
19584
19600
|
linkText: args5["link-text"],
|
|
@@ -19591,7 +19607,7 @@ var assetsUpdateCommand = defineCommand31({
|
|
|
19591
19607
|
callToAction: args5.cta,
|
|
19592
19608
|
text: args5.text
|
|
19593
19609
|
});
|
|
19594
|
-
await stageUpdate("google.asset.update", customerId,
|
|
19610
|
+
await stageUpdate("google.asset.update", customerId, target4, payload);
|
|
19595
19611
|
}
|
|
19596
19612
|
});
|
|
19597
19613
|
var assetsCommand = defineCommand31({
|
|
@@ -19904,8 +19920,8 @@ var campaignCriteriaCommand = defineCommand31({
|
|
|
19904
19920
|
},
|
|
19905
19921
|
run: async ({ args: args5 }) => {
|
|
19906
19922
|
const customerId = requireCustomerId(args5);
|
|
19907
|
-
const
|
|
19908
|
-
await stageUpdate("google.campaignCriterion.update", customerId,
|
|
19923
|
+
const target4 = requireTarget(args5, "campaign criterion");
|
|
19924
|
+
await stageUpdate("google.campaignCriterion.update", customerId, target4, {
|
|
19909
19925
|
bidModifier: bidModifierFlag(args5["bid-modifier"])
|
|
19910
19926
|
});
|
|
19911
19927
|
}
|
|
@@ -20335,7 +20351,7 @@ async function stageLinkedinOps(rawOps, hints2) {
|
|
|
20335
20351
|
async function stageStatusChange(input) {
|
|
20336
20352
|
const payload = input.kind === "creative.update" ? { intendedStatus: input.status } : { status: input.status };
|
|
20337
20353
|
await stageLinkedinOps(
|
|
20338
|
-
input.targets.map((
|
|
20354
|
+
input.targets.map((target4) => ({ kind: input.kind, accountId: input.accountId, target: target4, payload }))
|
|
20339
20355
|
);
|
|
20340
20356
|
}
|
|
20341
20357
|
function requireTarget2(args5, entity) {
|
|
@@ -20343,17 +20359,17 @@ function requireTarget2(args5, entity) {
|
|
|
20343
20359
|
if (inverted !== void 0) {
|
|
20344
20360
|
failWriteValidation2(inverted);
|
|
20345
20361
|
}
|
|
20346
|
-
const
|
|
20347
|
-
const
|
|
20348
|
-
if (typeof
|
|
20362
|
+
const positionals2 = readPositionals(args5);
|
|
20363
|
+
const target4 = args5.id ?? args5.target ?? args5.ref ?? positionals2[0];
|
|
20364
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
20349
20365
|
failWriteValidation2(`pass the ${entity} id or URN as the positional argument`);
|
|
20350
20366
|
}
|
|
20351
|
-
if (
|
|
20367
|
+
if (positionals2.length > 1 || splitIdList(target4).length > 1) {
|
|
20352
20368
|
failWriteValidation2(
|
|
20353
20369
|
`this command takes one ${entity} id \u2014 run it once per id. Only pause/resume/archive and 'creatives update' accept several ids in one call.`
|
|
20354
20370
|
);
|
|
20355
20371
|
}
|
|
20356
|
-
return
|
|
20372
|
+
return target4;
|
|
20357
20373
|
}
|
|
20358
20374
|
function readPositionals(args5) {
|
|
20359
20375
|
if (!Array.isArray(args5._)) {
|
|
@@ -20371,11 +20387,11 @@ function idsFileEntries(path49) {
|
|
|
20371
20387
|
return readFileSync5(path49, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
20372
20388
|
}
|
|
20373
20389
|
function requireTargets(args5, entity) {
|
|
20374
|
-
const
|
|
20390
|
+
const positionals2 = readPositionals(args5);
|
|
20375
20391
|
const named = [args5.id, args5.target, args5.ref].filter(
|
|
20376
20392
|
(value) => typeof value === "string" && value.length > 0
|
|
20377
20393
|
);
|
|
20378
|
-
const fromArgs =
|
|
20394
|
+
const fromArgs = positionals2.length > 0 ? positionals2 : named;
|
|
20379
20395
|
const targets = [.../* @__PURE__ */ new Set([...fromArgs.flatMap(splitIdList), ...idsFileEntries(args5["ids-file"])])];
|
|
20380
20396
|
if (targets.length === 0) {
|
|
20381
20397
|
failWriteValidation2(
|
|
@@ -21319,9 +21335,9 @@ Example: baker ads linkedin campaigns create --name "ABM Tier-1" --group li_temp
|
|
|
21319
21335
|
await stageOp({ kind: "campaign.create", accountId, payload });
|
|
21320
21336
|
}
|
|
21321
21337
|
});
|
|
21322
|
-
function campaignUpdatePayloadFromFlags(args5,
|
|
21338
|
+
function campaignUpdatePayloadFromFlags(args5, target4, file) {
|
|
21323
21339
|
const flags = campaignPayloadFromFlags(args5);
|
|
21324
|
-
if (!
|
|
21340
|
+
if (!target4.startsWith(TEMP_REF_PREFIX)) {
|
|
21325
21341
|
flags.campaignGroup = void 0;
|
|
21326
21342
|
flags.type = void 0;
|
|
21327
21343
|
flags.locale = void 0;
|
|
@@ -21342,9 +21358,9 @@ Example: baker ads linkedin campaigns update 123456 --daily-budget 100 --currenc
|
|
|
21342
21358
|
},
|
|
21343
21359
|
run: async ({ args: args5 }) => {
|
|
21344
21360
|
const accountId = bareAccountId(args5);
|
|
21345
|
-
const
|
|
21346
|
-
const payload = campaignUpdatePayloadFromFlags(args5,
|
|
21347
|
-
await stageOp({ kind: "campaign.update", accountId, target:
|
|
21361
|
+
const target4 = requireTarget2(args5, "campaign");
|
|
21362
|
+
const payload = campaignUpdatePayloadFromFlags(args5, target4, loadJsonFileArg2(args5.file));
|
|
21363
|
+
await stageOp({ kind: "campaign.update", accountId, target: target4, payload });
|
|
21348
21364
|
}
|
|
21349
21365
|
});
|
|
21350
21366
|
function statusSugarCommand(entity, kind, name) {
|
|
@@ -21491,11 +21507,11 @@ Examples:
|
|
|
21491
21507
|
file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
|
|
21492
21508
|
},
|
|
21493
21509
|
run: async ({ args: args5, rawArgs }) => {
|
|
21494
|
-
const { accountId, target:
|
|
21510
|
+
const { accountId, target: target4 } = accountTrackingTarget(args5);
|
|
21495
21511
|
await stageOp({
|
|
21496
21512
|
kind: "trackingParams.set",
|
|
21497
21513
|
accountId,
|
|
21498
|
-
target:
|
|
21514
|
+
target: target4,
|
|
21499
21515
|
payload: trackingParamsPayload(args5, rawArgs)
|
|
21500
21516
|
});
|
|
21501
21517
|
}
|
|
@@ -21783,7 +21799,7 @@ Examples:
|
|
|
21783
21799
|
campaign: args5.campaign,
|
|
21784
21800
|
content: Object.keys(content).length > 0 ? content : void 0
|
|
21785
21801
|
});
|
|
21786
|
-
await stageLinkedinOps(targets.map((
|
|
21802
|
+
await stageLinkedinOps(targets.map((target4) => ({ kind: "creative.update", accountId, target: target4, payload })));
|
|
21787
21803
|
}
|
|
21788
21804
|
});
|
|
21789
21805
|
var AUDIENCE_TYPES2 = ["company-list", "user-list", "retargeting", "engagement"];
|
|
@@ -21807,7 +21823,7 @@ Example: baker ads linkedin audiences create --name "ABM Tier-1" --type company-
|
|
|
21807
21823
|
},
|
|
21808
21824
|
run: async ({ args: args5 }) => {
|
|
21809
21825
|
const accountId = bareAccountId(args5);
|
|
21810
|
-
const
|
|
21826
|
+
const list3 = parseListFileArg(args5["list-file"], INLINE_ROWS_MAX);
|
|
21811
21827
|
const raw = args5.file ? loadJsonFileArg2(args5.file) : void 0;
|
|
21812
21828
|
await stageOp({
|
|
21813
21829
|
kind: "audience.create",
|
|
@@ -21815,7 +21831,7 @@ Example: baker ads linkedin audiences create --name "ABM Tier-1" --type company-
|
|
|
21815
21831
|
payload: {
|
|
21816
21832
|
name: args5.name,
|
|
21817
21833
|
audienceType: args5.type,
|
|
21818
|
-
...
|
|
21834
|
+
...list3 ? { listColumns: list3.columns, listRows: list3.rows } : {},
|
|
21819
21835
|
...raw ? { raw } : {}
|
|
21820
21836
|
}
|
|
21821
21837
|
});
|
|
@@ -21834,8 +21850,8 @@ Example: baker ads linkedin audiences upload urn:li:dmpSegment:42 --list-file mo
|
|
|
21834
21850
|
},
|
|
21835
21851
|
run: async ({ args: args5 }) => {
|
|
21836
21852
|
const accountId = bareAccountId(args5);
|
|
21837
|
-
const
|
|
21838
|
-
if (!
|
|
21853
|
+
const list3 = parseListFileArg(args5["list-file"], INLINE_ROWS_MAX);
|
|
21854
|
+
if (!list3) {
|
|
21839
21855
|
failWriteValidation2("--list-file is required");
|
|
21840
21856
|
}
|
|
21841
21857
|
await stageOp({
|
|
@@ -21843,8 +21859,8 @@ Example: baker ads linkedin audiences upload urn:li:dmpSegment:42 --list-file mo
|
|
|
21843
21859
|
accountId,
|
|
21844
21860
|
payload: {
|
|
21845
21861
|
segment: requireTarget2(args5, "audience segment"),
|
|
21846
|
-
listColumns:
|
|
21847
|
-
listRows:
|
|
21862
|
+
listColumns: list3.columns,
|
|
21863
|
+
listRows: list3.rows
|
|
21848
21864
|
}
|
|
21849
21865
|
});
|
|
21850
21866
|
}
|
|
@@ -26040,11 +26056,11 @@ function requireTarget3(args5, entity) {
|
|
|
26040
26056
|
failWriteValidation3(inverted);
|
|
26041
26057
|
}
|
|
26042
26058
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
26043
|
-
const
|
|
26044
|
-
if (typeof
|
|
26059
|
+
const target4 = args5.id ?? args5.target ?? args5.ref ?? positional;
|
|
26060
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
26045
26061
|
failWriteValidation3(`pass the ${entity} id as the positional argument`);
|
|
26046
26062
|
}
|
|
26047
|
-
return
|
|
26063
|
+
return target4;
|
|
26048
26064
|
}
|
|
26049
26065
|
async function stageOp2(raw) {
|
|
26050
26066
|
const preflight = metaDraftOpInputSchema.safeParse(raw);
|
|
@@ -28233,13 +28249,13 @@ async function resolveXAccountId(args5) {
|
|
|
28233
28249
|
});
|
|
28234
28250
|
process.exit(1);
|
|
28235
28251
|
}
|
|
28236
|
-
const
|
|
28252
|
+
const list3 = accounts.map((a) => ` ${a.id} ${a.name}`).join("\n");
|
|
28237
28253
|
writeAdsJson({
|
|
28238
28254
|
ok: false,
|
|
28239
28255
|
error: {
|
|
28240
28256
|
code: "MULTIPLE_ACCOUNTS",
|
|
28241
28257
|
message: `Multiple X Ads accounts found. Pass --account-id or set BAKER_X_ADS_ACCOUNT_ID:
|
|
28242
|
-
${
|
|
28258
|
+
${list3}`
|
|
28243
28259
|
}
|
|
28244
28260
|
});
|
|
28245
28261
|
process.exit(1);
|
|
@@ -30326,10 +30342,10 @@ function wallClockAsUtc(instant, timeZone) {
|
|
|
30326
30342
|
}
|
|
30327
30343
|
function accountMidnightIso(daysAgo, timeZone, now = /* @__PURE__ */ new Date()) {
|
|
30328
30344
|
const localNow = new Date(wallClockAsUtc(now, timeZone));
|
|
30329
|
-
const
|
|
30330
|
-
let instant =
|
|
30345
|
+
const target4 = Date.UTC(localNow.getUTCFullYear(), localNow.getUTCMonth(), localNow.getUTCDate() - daysAgo, 0, 0, 0);
|
|
30346
|
+
let instant = target4;
|
|
30331
30347
|
for (let i = 0; i < 2; i++) {
|
|
30332
|
-
instant =
|
|
30348
|
+
instant = target4 - (wallClockAsUtc(new Date(instant), timeZone) - instant);
|
|
30333
30349
|
}
|
|
30334
30350
|
return isoSeconds(new Date(instant));
|
|
30335
30351
|
}
|
|
@@ -31839,12 +31855,12 @@ function setFromRename(args5, existing) {
|
|
|
31839
31855
|
}
|
|
31840
31856
|
function conversionsWrite(args5, existing) {
|
|
31841
31857
|
const set = [...setFromEvents(args5, existing), ...setFromRename(args5, existing)];
|
|
31842
|
-
const
|
|
31858
|
+
const remove2 = [
|
|
31843
31859
|
...args5.removeKeys,
|
|
31844
31860
|
...args5.removeName === void 0 ? [] : under(args5.removeName, existing).map((row) => row.eventKey)
|
|
31845
31861
|
];
|
|
31846
|
-
if (set.length === 0 &&
|
|
31847
|
-
return { ...set.length > 0 ? { set } : {}, ...
|
|
31862
|
+
if (set.length === 0 && remove2.length === 0) return null;
|
|
31863
|
+
return { ...set.length > 0 ? { set } : {}, ...remove2.length > 0 ? { remove: remove2 } : {} };
|
|
31848
31864
|
}
|
|
31849
31865
|
|
|
31850
31866
|
// src/commands/analytics/conversionHints.ts
|
|
@@ -31907,9 +31923,9 @@ function mergeStoredWithCounts(stored, reported) {
|
|
|
31907
31923
|
const counts = new Map(reported.map((row) => [row.name, row]));
|
|
31908
31924
|
const groups = /* @__PURE__ */ new Map();
|
|
31909
31925
|
for (const row of stored) {
|
|
31910
|
-
const
|
|
31911
|
-
|
|
31912
|
-
groups.set(row.name,
|
|
31926
|
+
const group2 = groups.get(row.name) ?? [];
|
|
31927
|
+
group2.push(row);
|
|
31928
|
+
groups.set(row.name, group2);
|
|
31913
31929
|
}
|
|
31914
31930
|
return [...groups.entries()].map(([name, rows]) => {
|
|
31915
31931
|
const modes = new Set(rows.map((row) => row.countMode));
|
|
@@ -32709,7 +32725,7 @@ import { defineCommand as defineCommand97 } from "citty";
|
|
|
32709
32725
|
var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
|
|
32710
32726
|
function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
32711
32727
|
const set = parseSetFlags(raw, argv, now);
|
|
32712
|
-
const
|
|
32728
|
+
const remove2 = onlyOnce(raw.remove, "--remove", argv);
|
|
32713
32729
|
const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
32714
32730
|
if (days2 !== void 0 && (!Number.isInteger(days2) || days2 <= 0 || days2 > 400)) {
|
|
32715
32731
|
throw new ConversionArgsError("--days must be a whole number of days, from 1 to 400.");
|
|
@@ -32725,7 +32741,7 @@ function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
|
32725
32741
|
}
|
|
32726
32742
|
return {
|
|
32727
32743
|
...set === void 0 ? {} : { set },
|
|
32728
|
-
...
|
|
32744
|
+
...remove2 === void 0 ? {} : { remove: remove2 },
|
|
32729
32745
|
...days2 === void 0 ? {} : { days: days2 },
|
|
32730
32746
|
...uploads === void 0 ? {} : { uploads },
|
|
32731
32747
|
...raw.failed === true ? { failedOnly: true } : {},
|
|
@@ -35874,14 +35890,14 @@ function undisambiguatedSubsets(faces) {
|
|
|
35874
35890
|
}
|
|
35875
35891
|
function suggestFamilies(wanted, catalogue, limit2 = 5) {
|
|
35876
35892
|
const key = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
35877
|
-
const
|
|
35878
|
-
if (!
|
|
35879
|
-
const words2 =
|
|
35893
|
+
const target4 = key(wanted);
|
|
35894
|
+
if (!target4) return [];
|
|
35895
|
+
const words2 = target4.split(" ");
|
|
35880
35896
|
const scored = catalogue.map((family) => {
|
|
35881
35897
|
const candidate = key(family);
|
|
35882
|
-
if (candidate ===
|
|
35883
|
-
if (candidate.startsWith(
|
|
35884
|
-
if (candidate.includes(
|
|
35898
|
+
if (candidate === target4) return { family, score: 0 };
|
|
35899
|
+
if (candidate.startsWith(target4)) return { family, score: 1 };
|
|
35900
|
+
if (candidate.includes(target4)) return { family, score: 2 };
|
|
35885
35901
|
const shared = words2.filter((w) => w.length > 2 && candidate.includes(w)).length;
|
|
35886
35902
|
return { family, score: shared > 0 ? 3 + (words2.length - shared) : Number.POSITIVE_INFINITY };
|
|
35887
35903
|
}).filter((c) => Number.isFinite(c.score)).sort((a, b) => a.score - b.score || a.family.localeCompare(b.family));
|
|
@@ -35942,8 +35958,8 @@ async function resolveBrandFaces(family, weights, subsets, deps, styles = ["norm
|
|
|
35942
35958
|
function rebaseFontFaceSrc(block2, fromDir, toDir = "src/styles") {
|
|
35943
35959
|
return block2.replace(/url\(\s*(['"]?)([^'")]+)\1\s*\)/gi, (whole, _quote, href) => {
|
|
35944
35960
|
if (!isRepoFontHref(href)) return whole;
|
|
35945
|
-
const
|
|
35946
|
-
return `url('${posix.relative(toDir,
|
|
35961
|
+
const target4 = posix.normalize(posix.join(fromDir, href));
|
|
35962
|
+
return `url('${posix.relative(toDir, target4)}')`;
|
|
35947
35963
|
});
|
|
35948
35964
|
}
|
|
35949
35965
|
function declaredFontFaces(source) {
|
|
@@ -36121,12 +36137,12 @@ function declaredWeights(body) {
|
|
|
36121
36137
|
return range;
|
|
36122
36138
|
}
|
|
36123
36139
|
function selfHostedWeights(css, family) {
|
|
36124
|
-
const
|
|
36140
|
+
const target4 = normalizeFamily(family);
|
|
36125
36141
|
const weights = /* @__PURE__ */ new Set();
|
|
36126
36142
|
for (const rule of stripCssComments(css).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36127
36143
|
const body = rule[1] ?? "";
|
|
36128
36144
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36129
|
-
if (!declared || normalizeFamily(declared) !==
|
|
36145
|
+
if (!declared || normalizeFamily(declared) !== target4) continue;
|
|
36130
36146
|
for (const weight of declaredWeights(body)) weights.add(weight);
|
|
36131
36147
|
}
|
|
36132
36148
|
return [...weights].sort((a, b) => a - b);
|
|
@@ -36136,12 +36152,12 @@ function fontFileSubset(href) {
|
|
|
36136
36152
|
return /^[A-Za-z0-9]+-[1-9]00(?:italic)?-([\w-]+)\.woff2$/.exec(file)?.[1] ?? null;
|
|
36137
36153
|
}
|
|
36138
36154
|
function selfHostedSubsets(css, family) {
|
|
36139
|
-
const
|
|
36155
|
+
const target4 = normalizeFamily(family);
|
|
36140
36156
|
const subsets = /* @__PURE__ */ new Set();
|
|
36141
36157
|
for (const rule of stripCssComments(css).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36142
36158
|
const body = rule[1] ?? "";
|
|
36143
36159
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36144
|
-
if (!declared || normalizeFamily(declared) !==
|
|
36160
|
+
if (!declared || normalizeFamily(declared) !== target4) continue;
|
|
36145
36161
|
for (const url of body.matchAll(/url\(\s*['"]?([^'")]+)['"]?\s*\)/gi)) {
|
|
36146
36162
|
const subset = fontFileSubset(url[1] ?? "");
|
|
36147
36163
|
if (subset) subsets.add(subset);
|
|
@@ -36150,12 +36166,12 @@ function selfHostedSubsets(css, family) {
|
|
|
36150
36166
|
return [...subsets].sort();
|
|
36151
36167
|
}
|
|
36152
36168
|
function selfHostedStyles(css, family) {
|
|
36153
|
-
const
|
|
36169
|
+
const target4 = normalizeFamily(family);
|
|
36154
36170
|
const styles = /* @__PURE__ */ new Set();
|
|
36155
36171
|
for (const rule of stripCssComments(css).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36156
36172
|
const body = rule[1] ?? "";
|
|
36157
36173
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36158
|
-
if (declared && normalizeFamily(declared) ===
|
|
36174
|
+
if (declared && normalizeFamily(declared) === target4) styles.add(faceStyle(body));
|
|
36159
36175
|
}
|
|
36160
36176
|
return [...styles].sort();
|
|
36161
36177
|
}
|
|
@@ -36179,12 +36195,12 @@ function unresolvedBrandFamilies(css) {
|
|
|
36179
36195
|
return declared.filter((family) => !loaded.has(family)).map((family) => asAuthored(css, family));
|
|
36180
36196
|
}
|
|
36181
36197
|
function stripFontFaceBlocks(source, family, styles) {
|
|
36182
|
-
const
|
|
36198
|
+
const target4 = normalizeFamily(family);
|
|
36183
36199
|
const ranges = [];
|
|
36184
36200
|
for (const rule of stripCssComments(source).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36185
36201
|
const body = rule[1] ?? "";
|
|
36186
36202
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36187
|
-
if (!declared || normalizeFamily(declared) !==
|
|
36203
|
+
if (!declared || normalizeFamily(declared) !== target4 || rule.index === void 0) continue;
|
|
36188
36204
|
if (styles && !styles.has(faceStyle(body))) continue;
|
|
36189
36205
|
ranges.push([rule.index, rule.index + rule[0].length]);
|
|
36190
36206
|
}
|
|
@@ -36778,11 +36794,11 @@ function scoreRetentionRisk(videoNodes) {
|
|
|
36778
36794
|
};
|
|
36779
36795
|
}
|
|
36780
36796
|
function scoreMechanismClarity(allPromptText) {
|
|
36781
|
-
const
|
|
36797
|
+
const clear2 = MECHANISM_CUE.test(allPromptText);
|
|
36782
36798
|
return {
|
|
36783
36799
|
dimension: "mechanism_clarity",
|
|
36784
|
-
score:
|
|
36785
|
-
note:
|
|
36800
|
+
score: clear2 ? 1 : 0.4,
|
|
36801
|
+
note: clear2 ? "states a mechanism/proof" : "no clear 'why it works' \u2014 add the mechanism"
|
|
36786
36802
|
};
|
|
36787
36803
|
}
|
|
36788
36804
|
function clamp01(n) {
|
|
@@ -36795,8 +36811,8 @@ function staticCopyLines(nodes) {
|
|
|
36795
36811
|
return specimenText2.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
36796
36812
|
}
|
|
36797
36813
|
const gen = nodes.find((n) => n.type === "image_generate");
|
|
36798
|
-
const
|
|
36799
|
-
return
|
|
36814
|
+
const quoted2 = promptOf(gen).match(/"[^"]+"/g);
|
|
36815
|
+
return quoted2 ? quoted2.map((s) => s.slice(1, -1)) : [];
|
|
36800
36816
|
}
|
|
36801
36817
|
function scoreTextLegibilityRisk(nodes) {
|
|
36802
36818
|
const lines = staticCopyLines(nodes).length;
|
|
@@ -36945,8 +36961,8 @@ function canvasOutputsRoot(canvasFile, cwd = process.cwd(), exists2 = existsSync
|
|
|
36945
36961
|
const root = findWorkspaceRoot(path5.dirname(path5.resolve(cwd, canvasFile)), exists2) ?? cwd;
|
|
36946
36962
|
return path5.join(root, "canvas");
|
|
36947
36963
|
}
|
|
36948
|
-
function canonicalize(
|
|
36949
|
-
const abs = path5.resolve(
|
|
36964
|
+
function canonicalize(target4) {
|
|
36965
|
+
const abs = path5.resolve(target4);
|
|
36950
36966
|
let dir = abs;
|
|
36951
36967
|
for (; ; ) {
|
|
36952
36968
|
try {
|
|
@@ -36959,19 +36975,19 @@ function canonicalize(target2) {
|
|
|
36959
36975
|
}
|
|
36960
36976
|
}
|
|
36961
36977
|
}
|
|
36962
|
-
function isInside(root,
|
|
36963
|
-
const rel = path5.relative(root,
|
|
36978
|
+
function isInside(root, target4) {
|
|
36979
|
+
const rel = path5.relative(root, target4);
|
|
36964
36980
|
return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
36965
36981
|
}
|
|
36966
|
-
function toCanvasRelative(canvasDir,
|
|
36967
|
-
return path5.relative(canvasDir,
|
|
36982
|
+
function toCanvasRelative(canvasDir, target4) {
|
|
36983
|
+
return path5.relative(canvasDir, target4).split(path5.sep).join("/");
|
|
36968
36984
|
}
|
|
36969
36985
|
var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
|
|
36970
36986
|
function rewriteTarget(value, workspaceRoot) {
|
|
36971
36987
|
if (typeof value !== "string" || value.length === 0) return null;
|
|
36972
36988
|
if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path5.isAbsolute(value)) return null;
|
|
36973
|
-
const
|
|
36974
|
-
if (isInside(workspaceRoot,
|
|
36989
|
+
const target4 = canonicalize(value);
|
|
36990
|
+
if (isInside(workspaceRoot, target4)) return target4;
|
|
36975
36991
|
const fromRuntime = path5.relative(RUNTIME_WORKSPACE_ROOT, path5.normalize(value));
|
|
36976
36992
|
if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path5.isAbsolute(fromRuntime)) {
|
|
36977
36993
|
return path5.join(workspaceRoot, fromRuntime);
|
|
@@ -36997,9 +37013,9 @@ function normalizeCanvasPaths(canvas, canvasDir, workspaceRoot) {
|
|
|
36997
37013
|
}
|
|
36998
37014
|
const key = localPathParam(n);
|
|
36999
37015
|
if (!key) return node;
|
|
37000
|
-
const
|
|
37001
|
-
if (
|
|
37002
|
-
const to = toCanvasRelative(dir,
|
|
37016
|
+
const target4 = rewriteTarget(params2[key], root);
|
|
37017
|
+
if (target4 === null) return node;
|
|
37018
|
+
const to = toCanvasRelative(dir, target4);
|
|
37003
37019
|
rewrites.push({ nodeId, param: key, from: params2[key], to });
|
|
37004
37020
|
return { ...node, params: { ...params2, [key]: to } };
|
|
37005
37021
|
});
|
|
@@ -41302,8 +41318,8 @@ function mimeForFile(filePath) {
|
|
|
41302
41318
|
function toPosix(p) {
|
|
41303
41319
|
return p.split(path14.sep).join("/");
|
|
41304
41320
|
}
|
|
41305
|
-
function isInside2(dir,
|
|
41306
|
-
const rel = path14.relative(dir,
|
|
41321
|
+
function isInside2(dir, target4) {
|
|
41322
|
+
const rel = path14.relative(dir, target4);
|
|
41307
41323
|
return !rel.startsWith("..") && !path14.isAbsolute(rel);
|
|
41308
41324
|
}
|
|
41309
41325
|
function localPathRefsFromCanvas(parsed) {
|
|
@@ -41419,11 +41435,11 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
41419
41435
|
if (path14.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
41420
41436
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
41421
41437
|
}
|
|
41422
|
-
const
|
|
41423
|
-
if (
|
|
41438
|
+
const target4 = path14.resolve(resolvedTarget, entry.path);
|
|
41439
|
+
if (target4 !== resolvedTarget && !target4.startsWith(resolvedTarget + path14.sep)) {
|
|
41424
41440
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
41425
41441
|
}
|
|
41426
|
-
const existing = await readFile10(
|
|
41442
|
+
const existing = await readFile10(target4).catch(() => null);
|
|
41427
41443
|
if (existing) {
|
|
41428
41444
|
if (sha256Hex(existing) === entry.sha256) {
|
|
41429
41445
|
upToDate.push(entry.path);
|
|
@@ -41434,19 +41450,19 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
41434
41450
|
continue;
|
|
41435
41451
|
}
|
|
41436
41452
|
}
|
|
41437
|
-
planned.push({ entry, target:
|
|
41453
|
+
planned.push({ entry, target: target4 });
|
|
41438
41454
|
}
|
|
41439
41455
|
if (conflicts.length > 0) throw new SnapshotConflictError(conflicts);
|
|
41440
41456
|
const restored = [];
|
|
41441
|
-
for (const { entry, target:
|
|
41457
|
+
for (const { entry, target: target4 } of planned) {
|
|
41442
41458
|
const res = await fetch(entry.url);
|
|
41443
41459
|
if (!res.ok) throw new Error(`snapshot download failed for ${entry.path}: ${res.status} ${res.statusText}`);
|
|
41444
41460
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
41445
41461
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
41446
41462
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
41447
41463
|
}
|
|
41448
|
-
await mkdir5(path14.dirname(
|
|
41449
|
-
await writeFile7(
|
|
41464
|
+
await mkdir5(path14.dirname(target4), { recursive: true });
|
|
41465
|
+
await writeFile7(target4, bytes);
|
|
41450
41466
|
restored.push(entry.path);
|
|
41451
41467
|
}
|
|
41452
41468
|
return { canvasPath: path14.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
@@ -43116,9 +43132,9 @@ async function resolveCastAvatars(flag3) {
|
|
|
43116
43132
|
}
|
|
43117
43133
|
|
|
43118
43134
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
43119
|
-
async function fileExists(
|
|
43135
|
+
async function fileExists(target4) {
|
|
43120
43136
|
try {
|
|
43121
|
-
await access(
|
|
43137
|
+
await access(target4);
|
|
43122
43138
|
return true;
|
|
43123
43139
|
} catch {
|
|
43124
43140
|
return false;
|
|
@@ -43844,8 +43860,8 @@ function beatSeconds(line, videoModel) {
|
|
|
43844
43860
|
}
|
|
43845
43861
|
var BRAND_PLATE = "A solid flat brand colour plate \u2014 an end card. No people, no objects, no scenery, no text of any kind.";
|
|
43846
43862
|
var ASKS_FOR_LEGIBLE = /\b(focus on the (number|amount|total|price|figure|text)|readable|legible|clearly (shows?|visible)|highlighted (number|amount|total)|showing the (number|amount|total|price))\b/i;
|
|
43847
|
-
function briefWantsLegibleText(
|
|
43848
|
-
return ASKS_FOR_LEGIBLE.test(
|
|
43863
|
+
function briefWantsLegibleText(show2) {
|
|
43864
|
+
return ASKS_FOR_LEGIBLE.test(show2);
|
|
43849
43865
|
}
|
|
43850
43866
|
var SELF_INTRODUCTION = /\b([Ss]oy|[Mm]e llamo|[Mm]i nombre es|[Ss]ou|[Jj]e m'appelle|[Jj]e suis|[Mm]i chiamo|[Ss]ono|[Ii]ch bin|[Ii]'m|[Ii] am|[Mm]y name is)\s+[A-ZÁÉÍÓÚÑ]/;
|
|
43851
43867
|
function lineIntroducesSpeaker(line) {
|
|
@@ -44520,7 +44536,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
44520
44536
|
if (flagAvatar) {
|
|
44521
44537
|
spec.data.cast = { ...spec.data.cast, avatar: flagAvatar };
|
|
44522
44538
|
}
|
|
44523
|
-
const contradicts = spec.data.beats.map((beat, i) => ({ i, show: beat.show })).filter(({ show }) => briefWantsLegibleText(
|
|
44539
|
+
const contradicts = spec.data.beats.map((beat, i) => ({ i, show: beat.show })).filter(({ show: show2 }) => briefWantsLegibleText(show2));
|
|
44524
44540
|
if (contradicts.length > 0) {
|
|
44525
44541
|
writeJson({
|
|
44526
44542
|
ok: false,
|
|
@@ -45204,8 +45220,8 @@ function referenceVideoExt(url, contentType) {
|
|
|
45204
45220
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
45205
45221
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
45206
45222
|
}
|
|
45207
|
-
async function fileExists2(
|
|
45208
|
-
return access2(
|
|
45223
|
+
async function fileExists2(target4) {
|
|
45224
|
+
return access2(target4).then(
|
|
45209
45225
|
() => true,
|
|
45210
45226
|
() => false
|
|
45211
45227
|
);
|
|
@@ -46523,8 +46539,8 @@ async function importedFiles(text2, file, root) {
|
|
|
46523
46539
|
for (const match of text2.matchAll(re2)) {
|
|
46524
46540
|
const spec = match[1];
|
|
46525
46541
|
if (spec === void 0) continue;
|
|
46526
|
-
const
|
|
46527
|
-
if (
|
|
46542
|
+
const target4 = await resolveSpecifier(spec, file, root);
|
|
46543
|
+
if (target4 !== null) out.push(target4);
|
|
46528
46544
|
}
|
|
46529
46545
|
}
|
|
46530
46546
|
return out;
|
|
@@ -46542,8 +46558,8 @@ async function landingGraphFiles(root, slug) {
|
|
|
46542
46558
|
continue;
|
|
46543
46559
|
}
|
|
46544
46560
|
seen.add(file);
|
|
46545
|
-
for (const
|
|
46546
|
-
if (!seen.has(
|
|
46561
|
+
for (const target4 of await importedFiles(text2, file, root)) {
|
|
46562
|
+
if (!seen.has(target4)) queue.push(target4);
|
|
46547
46563
|
}
|
|
46548
46564
|
}
|
|
46549
46565
|
return new Set([...seen].map((abs) => path29.relative(root, abs).split(path29.sep).join("/")));
|
|
@@ -46666,8 +46682,8 @@ function repointMoved(text2, opts) {
|
|
|
46666
46682
|
return text2.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
46667
46683
|
const abs = path31.resolve(opts.fromDir, spec);
|
|
46668
46684
|
const within = path31.relative(opts.movedFrom, abs);
|
|
46669
|
-
const
|
|
46670
|
-
return `${quote}${toSpecifier(opts.toDir,
|
|
46685
|
+
const target4 = within.startsWith("..") || path31.isAbsolute(within) ? abs : path31.resolve(opts.movedTo, within);
|
|
46686
|
+
return `${quote}${toSpecifier(opts.toDir, target4)}${quote}`;
|
|
46671
46687
|
});
|
|
46672
46688
|
}
|
|
46673
46689
|
|
|
@@ -46743,8 +46759,8 @@ function repointIntoArchive(text2, sourceAbs, destAbs, archivedBySource) {
|
|
|
46743
46759
|
const toDir = path32.dirname(destAbs);
|
|
46744
46760
|
return text2.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
|
|
46745
46761
|
const [specPath, suffix] = splitSuffix(spec);
|
|
46746
|
-
const
|
|
46747
|
-
const resolved = resolveInArchive(
|
|
46762
|
+
const target4 = path32.resolve(fromDir, specPath);
|
|
46763
|
+
const resolved = resolveInArchive(target4, archivedBySource) ?? resolveOnDisk(target4, isImportPosition(text2, offset));
|
|
46748
46764
|
if (resolved === null) return match;
|
|
46749
46765
|
const rel = posix2(path32.relative(toDir, resolved));
|
|
46750
46766
|
return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
|
|
@@ -46802,63 +46818,63 @@ async function promoteVariantFiles(opts) {
|
|
|
46802
46818
|
}
|
|
46803
46819
|
return written;
|
|
46804
46820
|
}
|
|
46805
|
-
function archiveRecord(
|
|
46821
|
+
function archiveRecord(target4, variantNumber) {
|
|
46806
46822
|
return `${JSON.stringify(
|
|
46807
46823
|
{
|
|
46808
|
-
experimentId:
|
|
46809
|
-
page:
|
|
46810
|
-
pageInternalId:
|
|
46811
|
-
variant:
|
|
46824
|
+
experimentId: target4.experimentId,
|
|
46825
|
+
page: target4.landingSlug,
|
|
46826
|
+
pageInternalId: target4.landingInternalId,
|
|
46827
|
+
variant: target4.variantSlug,
|
|
46812
46828
|
variantNumber,
|
|
46813
46829
|
// Which arm this snapshot is. On a control win the variant lost; on a
|
|
46814
46830
|
// variant win what lost is the page's own previous content, which never
|
|
46815
46831
|
// had a number of its own — so it is filed under the test that rejected
|
|
46816
46832
|
// it, which is the only number that means anything about it.
|
|
46817
|
-
arm:
|
|
46833
|
+
arm: target4.survivor === "variant" ? "page-before-this-test" : "variant"
|
|
46818
46834
|
},
|
|
46819
46835
|
null,
|
|
46820
46836
|
2
|
|
46821
46837
|
)}
|
|
46822
46838
|
`;
|
|
46823
46839
|
}
|
|
46824
|
-
async function foldExperiment(root,
|
|
46825
|
-
const pageDir = path32.resolve(root, "src/pages",
|
|
46826
|
-
const variantDir = path32.resolve(root, "src/pages",
|
|
46827
|
-
const variantNumber = variantNumberOf(
|
|
46840
|
+
async function foldExperiment(root, target4) {
|
|
46841
|
+
const pageDir = path32.resolve(root, "src/pages", target4.landingSlug);
|
|
46842
|
+
const variantDir = path32.resolve(root, "src/pages", target4.variantSlug);
|
|
46843
|
+
const variantNumber = variantNumberOf(target4.variantSlug);
|
|
46828
46844
|
if (variantNumber === null) {
|
|
46829
46845
|
return {
|
|
46830
|
-
error: `\u201C${
|
|
46846
|
+
error: `\u201C${target4.variantSlug}\u201D is not a variant of \u201C${target4.landingSlug}\u201D, so there is nothing to fold`
|
|
46831
46847
|
};
|
|
46832
46848
|
}
|
|
46833
46849
|
if (!await isDir(pageDir)) {
|
|
46834
|
-
return { error: `There is no page at src/pages/${
|
|
46850
|
+
return { error: `There is no page at src/pages/${target4.landingSlug}/` };
|
|
46835
46851
|
}
|
|
46836
46852
|
if (!await isDir(variantDir)) {
|
|
46837
|
-
return { error: `src/pages/${
|
|
46853
|
+
return { error: `src/pages/${target4.variantSlug}/ is already gone \u2014 this test looks folded in already` };
|
|
46838
46854
|
}
|
|
46839
|
-
const archiveKey =
|
|
46855
|
+
const archiveKey = target4.landingInternalId ?? target4.landingSlug;
|
|
46840
46856
|
const archiveDir = path32.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
|
|
46841
46857
|
await rm8(archiveDir, { recursive: true, force: true });
|
|
46842
46858
|
await mkdir9(archiveDir, { recursive: true });
|
|
46843
46859
|
const written = await archiveArm({
|
|
46844
46860
|
root,
|
|
46845
|
-
armDir:
|
|
46861
|
+
armDir: target4.survivor === "variant" ? pageDir : variantDir,
|
|
46846
46862
|
pageDir,
|
|
46847
46863
|
archiveDir,
|
|
46848
|
-
armSlug:
|
|
46864
|
+
armSlug: target4.survivor === "variant" ? target4.landingSlug : target4.variantSlug
|
|
46849
46865
|
});
|
|
46850
|
-
await writeFile12(path32.join(archiveDir, "_variant.json"), archiveRecord(
|
|
46866
|
+
await writeFile12(path32.join(archiveDir, "_variant.json"), archiveRecord(target4, variantNumber), "utf8");
|
|
46851
46867
|
written.push(posix2(path32.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
|
|
46852
|
-
if (
|
|
46868
|
+
if (target4.survivor === "variant") {
|
|
46853
46869
|
written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
|
|
46854
46870
|
}
|
|
46855
46871
|
await rm8(variantDir, { recursive: true, force: true });
|
|
46856
46872
|
return {
|
|
46857
|
-
experimentId:
|
|
46858
|
-
page:
|
|
46873
|
+
experimentId: target4.experimentId,
|
|
46874
|
+
page: target4.landingSlug,
|
|
46859
46875
|
archivedTo: posix2(path32.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
|
|
46860
46876
|
written,
|
|
46861
|
-
removed: [`src/pages/${
|
|
46877
|
+
removed: [`src/pages/${target4.variantSlug}`]
|
|
46862
46878
|
};
|
|
46863
46879
|
}
|
|
46864
46880
|
|
|
@@ -48362,9 +48378,9 @@ var foldCommand = defineCommand124({
|
|
|
48362
48378
|
}
|
|
48363
48379
|
const folded = [];
|
|
48364
48380
|
const failures = [];
|
|
48365
|
-
for (const
|
|
48366
|
-
const result = await foldExperiment(process.cwd(),
|
|
48367
|
-
if ("error" in result) failures.push(`${
|
|
48381
|
+
for (const target4 of owed) {
|
|
48382
|
+
const result = await foldExperiment(process.cwd(), target4);
|
|
48383
|
+
if ("error" in result) failures.push(`${target4.landingSlug}: ${result.error}`);
|
|
48368
48384
|
else folded.push(result);
|
|
48369
48385
|
}
|
|
48370
48386
|
if (folded.length > 0) {
|
|
@@ -49147,9 +49163,9 @@ function listPatch(shape, sideEffect, entries) {
|
|
|
49147
49163
|
function existingEntries(shape, sideEffect) {
|
|
49148
49164
|
const owner = shape.under ? sideEffect[shape.under] : sideEffect;
|
|
49149
49165
|
if (!owner || typeof owner !== "object") return [];
|
|
49150
|
-
const
|
|
49151
|
-
if (!Array.isArray(
|
|
49152
|
-
return
|
|
49166
|
+
const list3 = owner[shape.key];
|
|
49167
|
+
if (!Array.isArray(list3)) return [];
|
|
49168
|
+
return list3.filter((entry) => Boolean(entry) && typeof entry === "object");
|
|
49153
49169
|
}
|
|
49154
49170
|
function mergeEntries(shape, existing, incoming) {
|
|
49155
49171
|
const address = (entry) => {
|
|
@@ -49650,10 +49666,10 @@ function dropUnsetOptionals(sideEffect, path49) {
|
|
|
49650
49666
|
return [{ path: path49, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
49651
49667
|
});
|
|
49652
49668
|
}
|
|
49653
|
-
function fillNulledArrays(
|
|
49669
|
+
function fillNulledArrays(target4, prefix, path49) {
|
|
49654
49670
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
49655
|
-
if (!(key in
|
|
49656
|
-
|
|
49671
|
+
if (!(key in target4) || target4[key] !== null) return [];
|
|
49672
|
+
target4[key] = [];
|
|
49657
49673
|
return [{ path: path49, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
49658
49674
|
});
|
|
49659
49675
|
}
|
|
@@ -49679,9 +49695,9 @@ function sideEffectsOf(node) {
|
|
|
49679
49695
|
function normalizeSideEffect(sideEffect, where) {
|
|
49680
49696
|
const path49 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
49681
49697
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
49682
|
-
const
|
|
49683
|
-
if (!
|
|
49684
|
-
return fillNulledArrays(
|
|
49698
|
+
const target4 = owner ? sideEffect[owner] : sideEffect;
|
|
49699
|
+
if (!target4 || typeof target4 !== "object") return [];
|
|
49700
|
+
return fillNulledArrays(target4, owner ? `${owner}.` : "", path49);
|
|
49685
49701
|
});
|
|
49686
49702
|
return [...dropUnsetOptionals(sideEffect, path49), ...arrays, ...tidyEmailRecipients(sideEffect, path49)];
|
|
49687
49703
|
}
|
|
@@ -50871,13 +50887,13 @@ async function resolvePropertyId(args5) {
|
|
|
50871
50887
|
if (properties.length === 0) {
|
|
50872
50888
|
handleConnectionError("ga4");
|
|
50873
50889
|
}
|
|
50874
|
-
const
|
|
50890
|
+
const list3 = properties.map((p) => ` ${p.externalId} ${p.name}`).join("\n");
|
|
50875
50891
|
writeJsonEnvelope({
|
|
50876
50892
|
ok: false,
|
|
50877
50893
|
error: {
|
|
50878
50894
|
code: "MULTIPLE_PROPERTIES",
|
|
50879
50895
|
message: `Multiple properties found. Pass --property-id or set BAKER_GA4_PROPERTY_ID:
|
|
50880
|
-
${
|
|
50896
|
+
${list3}`
|
|
50881
50897
|
}
|
|
50882
50898
|
});
|
|
50883
50899
|
process.exit(1);
|
|
@@ -50970,11 +50986,11 @@ function failValidation3(message) {
|
|
|
50970
50986
|
}
|
|
50971
50987
|
function requireTarget5(args5, entity) {
|
|
50972
50988
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
50973
|
-
const
|
|
50974
|
-
if (typeof
|
|
50989
|
+
const target4 = args5.id ?? args5.target ?? positional;
|
|
50990
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
50975
50991
|
failValidation3(`pass the ${entity} id as the positional argument`);
|
|
50976
50992
|
}
|
|
50977
|
-
return
|
|
50993
|
+
return target4;
|
|
50978
50994
|
}
|
|
50979
50995
|
function readJsonSource(args5, flag3) {
|
|
50980
50996
|
const inline = args5[flag3];
|
|
@@ -51968,11 +51984,11 @@ Examples:
|
|
|
51968
51984
|
"property-id": propertyArg
|
|
51969
51985
|
},
|
|
51970
51986
|
run: async ({ args: args5 }) => {
|
|
51971
|
-
const
|
|
51987
|
+
const target4 = requireTarget5(args5, "audience id");
|
|
51972
51988
|
const payload = loadJsonArg(args5);
|
|
51973
51989
|
await stageOp3({
|
|
51974
51990
|
kind: "ga4.audience.update",
|
|
51975
|
-
target:
|
|
51991
|
+
target: target4,
|
|
51976
51992
|
payload,
|
|
51977
51993
|
...withProperty(args5)
|
|
51978
51994
|
});
|
|
@@ -52101,13 +52117,13 @@ Examples:
|
|
|
52101
52117
|
"property-id": propertyArg
|
|
52102
52118
|
},
|
|
52103
52119
|
run: async ({ args: args5 }) => {
|
|
52104
|
-
const
|
|
52120
|
+
const target4 = requireTarget5(args5, "Google Ads link id");
|
|
52105
52121
|
if (typeof args5["ads-personalization"] !== "string") {
|
|
52106
52122
|
failValidation3("pass --ads-personalization true|false \u2014 it is the only thing a link update can change");
|
|
52107
52123
|
}
|
|
52108
52124
|
await stageOp3({
|
|
52109
52125
|
kind: "ga4.googleAdsLink.update",
|
|
52110
|
-
target:
|
|
52126
|
+
target: target4,
|
|
52111
52127
|
payload: { adsPersonalizationEnabled: booleanArg(args5["ads-personalization"], "ads-personalization") },
|
|
52112
52128
|
...withProperty(args5)
|
|
52113
52129
|
});
|
|
@@ -52342,13 +52358,13 @@ async function resolveSiteUrl(args5) {
|
|
|
52342
52358
|
if (sites.length === 0) {
|
|
52343
52359
|
handleConnectionError("gsc");
|
|
52344
52360
|
}
|
|
52345
|
-
const
|
|
52361
|
+
const list3 = sites.map((s) => ` ${s.siteUrl} (${s.permissionLevel})`).join("\n");
|
|
52346
52362
|
writeJsonEnvelope({
|
|
52347
52363
|
ok: false,
|
|
52348
52364
|
error: {
|
|
52349
52365
|
code: "MULTIPLE_SITES",
|
|
52350
52366
|
message: `Multiple sites found. Pass --site-url or set BAKER_GSC_SITE_URL:
|
|
52351
|
-
${
|
|
52367
|
+
${list3}`
|
|
52352
52368
|
}
|
|
52353
52369
|
});
|
|
52354
52370
|
process.exit(1);
|
|
@@ -53338,7 +53354,7 @@ function propertiesCommand2(object) {
|
|
|
53338
53354
|
object
|
|
53339
53355
|
});
|
|
53340
53356
|
const { properties } = response.data;
|
|
53341
|
-
const operators = Object.entries(HUBSPOT_OPERATORS).map(([kind,
|
|
53357
|
+
const operators = Object.entries(HUBSPOT_OPERATORS).map(([kind, list3]) => `${kind}: ${list3.map((operator) => operator.value).join(", ")}`).join(" \xB7 ");
|
|
53342
53358
|
const objectFlag = object === "contact" ? "" : ` --object ${object}`;
|
|
53343
53359
|
const hints2 = properties.length === 0 ? [`This account has no visible ${object} property, so there is nothing an event could watch.`] : [
|
|
53344
53360
|
`Pick the property and the condition that mean the outcome, then \`baker analytics sources --create-hubspot${objectFlag} --property <name> [--operator <op>] --value <value>\u2026\` (\`--value\` repeats for a list). Operators by kind \u2014 ${operators}. Counting starts from creation: a ${object} already satisfying it is not counted until it leaves and comes back.`
|
|
@@ -53922,17 +53938,17 @@ var dimensionsCommand = defineCommand147({
|
|
|
53922
53938
|
},
|
|
53923
53939
|
run: async ({ args: args5 }) => {
|
|
53924
53940
|
try {
|
|
53925
|
-
const
|
|
53926
|
-
if (!
|
|
53941
|
+
const target4 = args5.target;
|
|
53942
|
+
if (!target4) {
|
|
53927
53943
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "target argument is required" } });
|
|
53928
53944
|
process.exit(1);
|
|
53929
53945
|
}
|
|
53930
|
-
const buffer = await readImageBuffer(
|
|
53946
|
+
const buffer = await readImageBuffer(target4);
|
|
53931
53947
|
const dims = getDimensionsFromBuffer(buffer);
|
|
53932
53948
|
if (!dims) {
|
|
53933
53949
|
writeJson({
|
|
53934
53950
|
ok: false,
|
|
53935
|
-
error: { code: "IMAGE_PROCESSING_ERROR", message: `Could not extract dimensions from ${
|
|
53951
|
+
error: { code: "IMAGE_PROCESSING_ERROR", message: `Could not extract dimensions from ${target4}` }
|
|
53936
53952
|
});
|
|
53937
53953
|
process.exit(1);
|
|
53938
53954
|
}
|
|
@@ -53940,8 +53956,8 @@ var dimensionsCommand = defineCommand147({
|
|
|
53940
53956
|
{
|
|
53941
53957
|
ok: true,
|
|
53942
53958
|
data: {
|
|
53943
|
-
target:
|
|
53944
|
-
source: isRemoteUrl(
|
|
53959
|
+
target: target4,
|
|
53960
|
+
source: isRemoteUrl(target4) ? "url" : "file",
|
|
53945
53961
|
width: dims.width,
|
|
53946
53962
|
height: dims.height,
|
|
53947
53963
|
aspectRatio: Math.round(dims.aspectRatio * 1e4) / 1e4,
|
|
@@ -54070,15 +54086,15 @@ registerSchema({
|
|
|
54070
54086
|
var ValidationError3 = class extends Error {
|
|
54071
54087
|
};
|
|
54072
54088
|
var UnusableTargetError = class extends Error {
|
|
54073
|
-
constructor(
|
|
54074
|
-
super(`"${
|
|
54075
|
-
this.target =
|
|
54089
|
+
constructor(target4) {
|
|
54090
|
+
super(`"${target4}" is neither an image URL nor a library image id.`);
|
|
54091
|
+
this.target = target4;
|
|
54076
54092
|
}
|
|
54077
54093
|
};
|
|
54078
54094
|
function readTargets(args5) {
|
|
54079
|
-
const
|
|
54095
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
54080
54096
|
const named = typeof args5.targets === "string" ? [args5.targets] : [];
|
|
54081
|
-
const all =
|
|
54097
|
+
const all = positionals2.length > 0 ? positionals2 : named;
|
|
54082
54098
|
const seen = /* @__PURE__ */ new Set();
|
|
54083
54099
|
const out = [];
|
|
54084
54100
|
for (const value of all) {
|
|
@@ -54103,13 +54119,13 @@ function classify(raw) {
|
|
|
54103
54119
|
}
|
|
54104
54120
|
return { raw, kind: "imageId" };
|
|
54105
54121
|
}
|
|
54106
|
-
async function resolveTarget(
|
|
54107
|
-
if (
|
|
54108
|
-
return { input:
|
|
54122
|
+
async function resolveTarget(target4) {
|
|
54123
|
+
if (target4.kind === "url") {
|
|
54124
|
+
return { input: target4.raw, url: target4.raw, baseName: baseNameFromUrl(target4.raw) };
|
|
54109
54125
|
}
|
|
54110
|
-
const doc = await apiGet("/api/images/get", { id:
|
|
54111
|
-
const stem = sanitizeBaseName(doc.name.length > 0 ? doc.name :
|
|
54112
|
-
return { input:
|
|
54126
|
+
const doc = await apiGet("/api/images/get", { id: target4.raw });
|
|
54127
|
+
const stem = sanitizeBaseName(doc.name.length > 0 ? doc.name : target4.raw);
|
|
54128
|
+
return { input: target4.raw, url: doc.imageUrl, baseName: stem };
|
|
54113
54129
|
}
|
|
54114
54130
|
async function fetchBytes(url) {
|
|
54115
54131
|
return await fetchExternalBytes(url, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
@@ -54145,9 +54161,9 @@ function failureMessage(err, fallback) {
|
|
|
54145
54161
|
async function runDownloads(plan) {
|
|
54146
54162
|
const failed = [];
|
|
54147
54163
|
const fetched = [];
|
|
54148
|
-
for (const
|
|
54164
|
+
for (const target4 of plan.targets) {
|
|
54149
54165
|
try {
|
|
54150
|
-
const resolved = await resolveTarget(
|
|
54166
|
+
const resolved = await resolveTarget(target4);
|
|
54151
54167
|
const { buffer, contentType } = await fetchBytes(resolved.url);
|
|
54152
54168
|
fetched.push({
|
|
54153
54169
|
input: resolved.input,
|
|
@@ -54161,7 +54177,7 @@ async function runDownloads(plan) {
|
|
|
54161
54177
|
})
|
|
54162
54178
|
});
|
|
54163
54179
|
} catch (err) {
|
|
54164
|
-
failed.push({ input:
|
|
54180
|
+
failed.push({ input: target4.raw, error: failureMessage(err, "Download failed") });
|
|
54165
54181
|
}
|
|
54166
54182
|
}
|
|
54167
54183
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
@@ -54382,7 +54398,7 @@ function providerHitNormalizer(record, full) {
|
|
|
54382
54398
|
if (!full) {
|
|
54383
54399
|
return compact3;
|
|
54384
54400
|
}
|
|
54385
|
-
const
|
|
54401
|
+
const group2 = asRecord2(record.group);
|
|
54386
54402
|
return {
|
|
54387
54403
|
...compact3,
|
|
54388
54404
|
externalUrl: str(record.externalUrl),
|
|
@@ -54394,7 +54410,7 @@ function providerHitNormalizer(record, full) {
|
|
|
54394
54410
|
score: num(record.score),
|
|
54395
54411
|
deduped: typeof record.deduped === "boolean" ? record.deduped : void 0,
|
|
54396
54412
|
alsoInLibrary: str(record.alsoInLibrary),
|
|
54397
|
-
groupKey: str(
|
|
54413
|
+
groupKey: str(group2.key)
|
|
54398
54414
|
};
|
|
54399
54415
|
}
|
|
54400
54416
|
function readOutputFlags(args5) {
|
|
@@ -55732,18 +55748,18 @@ function findColorRangeInternal(data, ignoredColor = null, customThreshold) {
|
|
|
55732
55748
|
const color = { r: data[i], g: data[i + 1], b: data[i + 2] };
|
|
55733
55749
|
if (ignoredColor && colorDistance(color, ignoredColor) < threshold) continue;
|
|
55734
55750
|
let found = false;
|
|
55735
|
-
for (const
|
|
55736
|
-
const distance = colorDistance(
|
|
55737
|
-
const contrastRatio = getContrastRatio(
|
|
55751
|
+
for (const group2 of groups) {
|
|
55752
|
+
const distance = colorDistance(group2.color, color);
|
|
55753
|
+
const contrastRatio = getContrastRatio(group2.color, color);
|
|
55738
55754
|
let groupingThreshold = threshold;
|
|
55739
55755
|
if (contrastRatio > 3) groupingThreshold = Math.min(groupingThreshold, 8);
|
|
55740
|
-
const hueDistance = getHueDistance(
|
|
55756
|
+
const hueDistance = getHueDistance(group2.color, color);
|
|
55741
55757
|
if (hueDistance > 20) groupingThreshold = Math.min(groupingThreshold, 5);
|
|
55742
|
-
if (isHighlySaturated(color) && isHighlySaturated(
|
|
55758
|
+
if (isHighlySaturated(color) && isHighlySaturated(group2.color)) {
|
|
55743
55759
|
groupingThreshold = Math.min(groupingThreshold, 10);
|
|
55744
55760
|
}
|
|
55745
55761
|
if (distance < groupingThreshold) {
|
|
55746
|
-
|
|
55762
|
+
group2.count++;
|
|
55747
55763
|
found = true;
|
|
55748
55764
|
break;
|
|
55749
55765
|
}
|
|
@@ -55848,13 +55864,13 @@ function hasGradient(data) {
|
|
|
55848
55864
|
function perceivedLuminance(color) {
|
|
55849
55865
|
return (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255;
|
|
55850
55866
|
}
|
|
55851
|
-
function createSvgRecolorer(
|
|
55852
|
-
if (palette.length < 2) return () =>
|
|
55867
|
+
function createSvgRecolorer(target4, palette) {
|
|
55868
|
+
if (palette.length < 2) return () => target4;
|
|
55853
55869
|
const luminances = palette.map(perceivedLuminance);
|
|
55854
55870
|
const min = Math.min(...luminances);
|
|
55855
55871
|
const max = Math.max(...luminances);
|
|
55856
|
-
if (max - min < 0.05) return () =>
|
|
55857
|
-
const [h, s, targetLightness] = rgbToHsl(
|
|
55872
|
+
if (max - min < 0.05) return () => target4;
|
|
55873
|
+
const [h, s, targetLightness] = rgbToHsl(target4.r, target4.g, target4.b);
|
|
55858
55874
|
const lightnessRange = 0.75;
|
|
55859
55875
|
const minLightness = targetLightness >= 0.5 ? Math.max(0, targetLightness - lightnessRange) : targetLightness;
|
|
55860
55876
|
const maxLightness = targetLightness >= 0.5 ? targetLightness : Math.min(1, targetLightness + lightnessRange);
|
|
@@ -56848,18 +56864,18 @@ var uploadCommand = defineCommand167({
|
|
|
56848
56864
|
},
|
|
56849
56865
|
run: async ({ args: args5 }) => {
|
|
56850
56866
|
try {
|
|
56851
|
-
const
|
|
56852
|
-
if (!
|
|
56867
|
+
const target4 = args5.file;
|
|
56868
|
+
if (!target4) {
|
|
56853
56869
|
writeJson({
|
|
56854
56870
|
ok: false,
|
|
56855
56871
|
error: { code: "VALIDATION_ERROR", message: "File path or URL is required" }
|
|
56856
56872
|
});
|
|
56857
56873
|
process.exit(1);
|
|
56858
56874
|
}
|
|
56859
|
-
if (isRemoteUrl2(
|
|
56860
|
-
await uploadRemote(
|
|
56875
|
+
if (isRemoteUrl2(target4)) {
|
|
56876
|
+
await uploadRemote(target4, args5);
|
|
56861
56877
|
} else {
|
|
56862
|
-
await uploadLocal(
|
|
56878
|
+
await uploadLocal(target4, args5);
|
|
56863
56879
|
}
|
|
56864
56880
|
} catch (err) {
|
|
56865
56881
|
if (err instanceof ApiError) {
|
|
@@ -56871,7 +56887,7 @@ var uploadCommand = defineCommand167({
|
|
|
56871
56887
|
}
|
|
56872
56888
|
}
|
|
56873
56889
|
});
|
|
56874
|
-
async function uploadRemote(
|
|
56890
|
+
async function uploadRemote(target4, args5) {
|
|
56875
56891
|
const source = args5.source ?? "uploaded";
|
|
56876
56892
|
if (args5["dry-run"]) {
|
|
56877
56893
|
writeJson({
|
|
@@ -56879,7 +56895,7 @@ async function uploadRemote(target2, args5) {
|
|
|
56879
56895
|
dryRun: true,
|
|
56880
56896
|
operation: "images.upload (remote)",
|
|
56881
56897
|
params: {
|
|
56882
|
-
url:
|
|
56898
|
+
url: target4,
|
|
56883
56899
|
source,
|
|
56884
56900
|
externalId: args5["external-id"] ?? null,
|
|
56885
56901
|
externalUrl: args5["external-url"] ?? null,
|
|
@@ -56888,22 +56904,22 @@ async function uploadRemote(target2, args5) {
|
|
|
56888
56904
|
});
|
|
56889
56905
|
return;
|
|
56890
56906
|
}
|
|
56891
|
-
const body = { url:
|
|
56907
|
+
const body = { url: target4, source };
|
|
56892
56908
|
if (args5["external-id"]) body.externalId = args5["external-id"];
|
|
56893
56909
|
if (args5["external-url"]) body.externalUrl = args5["external-url"];
|
|
56894
56910
|
if (args5.context) body.descriptionContext = args5.context;
|
|
56895
56911
|
const data = await apiPost("/api/images/ingest", body);
|
|
56896
56912
|
writeJson({ ok: true, data });
|
|
56897
56913
|
}
|
|
56898
|
-
async function uploadLocal(
|
|
56899
|
-
const contentType = args5["content-type"] || detectImageContentType(
|
|
56914
|
+
async function uploadLocal(target4, args5) {
|
|
56915
|
+
const contentType = args5["content-type"] || detectImageContentType(target4);
|
|
56900
56916
|
if (args5["dry-run"]) {
|
|
56901
56917
|
writeJson({
|
|
56902
56918
|
ok: true,
|
|
56903
56919
|
dryRun: true,
|
|
56904
56920
|
operation: "images.upload (local)",
|
|
56905
56921
|
params: {
|
|
56906
|
-
file:
|
|
56922
|
+
file: target4,
|
|
56907
56923
|
contentType,
|
|
56908
56924
|
source: args5.source ?? null,
|
|
56909
56925
|
descriptionContext: args5.context ?? null
|
|
@@ -56912,7 +56928,7 @@ async function uploadLocal(target2, args5) {
|
|
|
56912
56928
|
return;
|
|
56913
56929
|
}
|
|
56914
56930
|
const data = await uploadLocalImage({
|
|
56915
|
-
file:
|
|
56931
|
+
file: target4,
|
|
56916
56932
|
contentType,
|
|
56917
56933
|
source: args5.source,
|
|
56918
56934
|
descriptionContext: args5.context
|
|
@@ -59201,7 +59217,7 @@ function classifyPreflightStatus(status) {
|
|
|
59201
59217
|
async function preflightProxyRoute(route, options = {}) {
|
|
59202
59218
|
if (route.kind !== "proxy") return { usable: true };
|
|
59203
59219
|
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
59204
|
-
const
|
|
59220
|
+
const target4 = options.target ?? "example.com:443";
|
|
59205
59221
|
const endpoint = new URL(route.server);
|
|
59206
59222
|
const auth = Buffer.from(`${route.username}:${route.password}`).toString("base64");
|
|
59207
59223
|
return await new Promise((resolve5) => {
|
|
@@ -59213,8 +59229,8 @@ async function preflightProxyRoute(route, options = {}) {
|
|
|
59213
59229
|
host: endpoint.hostname,
|
|
59214
59230
|
port: Number(endpoint.port),
|
|
59215
59231
|
method: "CONNECT",
|
|
59216
|
-
path:
|
|
59217
|
-
headers: { "Proxy-Authorization": `Basic ${auth}`, Host:
|
|
59232
|
+
path: target4,
|
|
59233
|
+
headers: { "Proxy-Authorization": `Basic ${auth}`, Host: target4 },
|
|
59218
59234
|
timeout: timeoutMs
|
|
59219
59235
|
});
|
|
59220
59236
|
request.on("connect", (response, socket) => {
|
|
@@ -60140,9 +60156,9 @@ function bandsCollide(a, b, margin, maxGap) {
|
|
|
60140
60156
|
const gap = Math.min(Math.abs(shrunkA.bottom - shrunkB.top), Math.abs(shrunkB.bottom - shrunkA.top));
|
|
60141
60157
|
return gap <= maxGap;
|
|
60142
60158
|
}
|
|
60143
|
-
function shouldPromoteToParent(
|
|
60144
|
-
const isRunt =
|
|
60145
|
-
return isRunt &&
|
|
60159
|
+
function shouldPromoteToParent(group2) {
|
|
60160
|
+
const isRunt = group2.childCount < 3 || group2.height < 80;
|
|
60161
|
+
return isRunt && group2.parentHeight < 1600;
|
|
60146
60162
|
}
|
|
60147
60163
|
|
|
60148
60164
|
// src/engine/landing-library/segment.ts
|
|
@@ -60361,35 +60377,35 @@ var inPageSegment = (options) => {
|
|
|
60361
60377
|
};
|
|
60362
60378
|
const clusterOnce = (groups2) => {
|
|
60363
60379
|
const buckets = [];
|
|
60364
|
-
for (const
|
|
60365
|
-
if (
|
|
60366
|
-
buckets.push([
|
|
60380
|
+
for (const group2 of groups2) {
|
|
60381
|
+
if (group2.sealed) {
|
|
60382
|
+
buckets.push([group2]);
|
|
60367
60383
|
continue;
|
|
60368
60384
|
}
|
|
60369
|
-
const
|
|
60385
|
+
const target4 = buckets.find(
|
|
60370
60386
|
(bucket) => bucket.some(
|
|
60371
60387
|
(member) => !member.sealed && geom.bandsCollide(
|
|
60372
60388
|
{ top: member.top, bottom: member.bottom },
|
|
60373
|
-
{ top:
|
|
60389
|
+
{ top: group2.top, bottom: group2.bottom },
|
|
60374
60390
|
options.collisionMargin,
|
|
60375
60391
|
gapThreshold
|
|
60376
60392
|
)
|
|
60377
60393
|
)
|
|
60378
60394
|
);
|
|
60379
|
-
if (
|
|
60380
|
-
else buckets.push([
|
|
60395
|
+
if (target4) target4.push(group2);
|
|
60396
|
+
else buckets.push([group2]);
|
|
60381
60397
|
}
|
|
60382
60398
|
if (buckets.length === groups2.length) return groups2;
|
|
60383
60399
|
return buckets.flatMap((bucket) => bucket.length === 1 ? [bucket[0]] : mergeBucket(bucket));
|
|
60384
60400
|
};
|
|
60385
|
-
let groups = leaves.map((
|
|
60386
|
-
root:
|
|
60387
|
-
top:
|
|
60388
|
-
bottom:
|
|
60389
|
-
left:
|
|
60390
|
-
right:
|
|
60391
|
-
height:
|
|
60392
|
-
leaves: [
|
|
60401
|
+
let groups = leaves.map((leaf2) => ({
|
|
60402
|
+
root: leaf2.element,
|
|
60403
|
+
top: leaf2.top,
|
|
60404
|
+
bottom: leaf2.bottom,
|
|
60405
|
+
left: leaf2.left,
|
|
60406
|
+
right: leaf2.right,
|
|
60407
|
+
height: leaf2.height,
|
|
60408
|
+
leaves: [leaf2],
|
|
60393
60409
|
sealed: false
|
|
60394
60410
|
}));
|
|
60395
60411
|
for (let pass = 0; pass < 40; pass++) {
|
|
@@ -60399,21 +60415,21 @@ var inPageSegment = (options) => {
|
|
|
60399
60415
|
}
|
|
60400
60416
|
for (let pass = 0; pass < 10; pass++) {
|
|
60401
60417
|
let promoted = false;
|
|
60402
|
-
groups = groups.map((
|
|
60403
|
-
const parent =
|
|
60404
|
-
if (!parent || parent === document.documentElement || parent === document.body) return
|
|
60418
|
+
groups = groups.map((group2) => {
|
|
60419
|
+
const parent = group2.root.parentElement;
|
|
60420
|
+
if (!parent || parent === document.documentElement || parent === document.body) return group2;
|
|
60405
60421
|
const parentBox = boxOf(parent);
|
|
60406
|
-
if (!parentBox) return
|
|
60422
|
+
if (!parentBox) return group2;
|
|
60407
60423
|
if (!geom.shouldPromoteToParent({
|
|
60408
|
-
childCount:
|
|
60409
|
-
height:
|
|
60424
|
+
childCount: group2.leaves.length,
|
|
60425
|
+
height: group2.height,
|
|
60410
60426
|
parentHeight: parentBox.height
|
|
60411
60427
|
})) {
|
|
60412
|
-
return
|
|
60428
|
+
return group2;
|
|
60413
60429
|
}
|
|
60414
60430
|
promoted = true;
|
|
60415
60431
|
return {
|
|
60416
|
-
...
|
|
60432
|
+
...group2,
|
|
60417
60433
|
root: parent,
|
|
60418
60434
|
top: parentBox.top,
|
|
60419
60435
|
bottom: parentBox.bottom,
|
|
@@ -60429,23 +60445,23 @@ var inPageSegment = (options) => {
|
|
|
60429
60445
|
const containsBox = (outer, inner) => outer.top - 4 <= inner.top && outer.bottom + 4 >= inner.bottom && outer.left - 4 <= inner.left && outer.right + 4 >= inner.right;
|
|
60430
60446
|
const deduped = [];
|
|
60431
60447
|
const area = (g) => (g.right - g.left) * g.height;
|
|
60432
|
-
for (const
|
|
60448
|
+
for (const group2 of groups.slice().sort((a, b) => area(b) - area(a) || b.leaves.length - a.leaves.length)) {
|
|
60433
60449
|
const duplicate = deduped.some(
|
|
60434
|
-
(kept) => kept.root ===
|
|
60450
|
+
(kept) => kept.root === group2.root || kept.root.contains(group2.root) || sameBox(kept, group2) || containsBox(kept, group2)
|
|
60435
60451
|
);
|
|
60436
|
-
if (!duplicate) deduped.push(
|
|
60452
|
+
if (!duplicate) deduped.push(group2);
|
|
60437
60453
|
}
|
|
60438
|
-
return deduped.filter((
|
|
60454
|
+
return deduped.filter((group2) => group2.height > 0 && group2.right - group2.left > 0).sort((a, b) => a.top - b.top).map((group2, index) => ({
|
|
60439
60455
|
index,
|
|
60440
|
-
selector: selectorFor(
|
|
60456
|
+
selector: selectorFor(group2.root),
|
|
60441
60457
|
rect: {
|
|
60442
|
-
top:
|
|
60443
|
-
left:
|
|
60444
|
-
width:
|
|
60445
|
-
height:
|
|
60458
|
+
top: group2.top,
|
|
60459
|
+
left: group2.left,
|
|
60460
|
+
width: group2.right - group2.left,
|
|
60461
|
+
height: group2.height
|
|
60446
60462
|
},
|
|
60447
|
-
leafCount:
|
|
60448
|
-
textPreview: visibleText(
|
|
60463
|
+
leafCount: group2.leaves.length,
|
|
60464
|
+
textPreview: visibleText(group2.root).slice(0, 200)
|
|
60449
60465
|
}));
|
|
60450
60466
|
};
|
|
60451
60467
|
|
|
@@ -60472,8 +60488,8 @@ async function captureMotionTake(browser, url, selector, timeoutMs = 45e3) {
|
|
|
60472
60488
|
await settleNavigation(page);
|
|
60473
60489
|
await page.waitForLoadState("networkidle", { timeout: 8e3 }).catch(() => void 0);
|
|
60474
60490
|
await settleConsent(page);
|
|
60475
|
-
const
|
|
60476
|
-
if (!await
|
|
60491
|
+
const target4 = page.locator(selector).first();
|
|
60492
|
+
if (!await target4.count().catch(() => 0)) return null;
|
|
60477
60493
|
await page.evaluate((sectionSelector) => {
|
|
60478
60494
|
const element = document.querySelector(sectionSelector);
|
|
60479
60495
|
if (!element) return;
|
|
@@ -60527,12 +60543,12 @@ async function aimAtSection(page, selector) {
|
|
|
60527
60543
|
}
|
|
60528
60544
|
async function hideFloatingFurniture(page, selector) {
|
|
60529
60545
|
await page.evaluate((sectionSelector) => {
|
|
60530
|
-
const
|
|
60531
|
-
if (!
|
|
60546
|
+
const target4 = document.querySelector(sectionSelector);
|
|
60547
|
+
if (!target4) return;
|
|
60532
60548
|
for (const element of Array.from(document.querySelectorAll("*"))) {
|
|
60533
60549
|
const position = getComputedStyle(element).position;
|
|
60534
60550
|
if (position !== "fixed" && position !== "sticky") continue;
|
|
60535
|
-
if (element.contains(
|
|
60551
|
+
if (element.contains(target4) || target4.contains(element) || element === target4) continue;
|
|
60536
60552
|
element.style.setProperty("visibility", "hidden", "important");
|
|
60537
60553
|
}
|
|
60538
60554
|
}, selector);
|
|
@@ -60589,9 +60605,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
60589
60605
|
await page.waitForTimeout(300);
|
|
60590
60606
|
if (!wholePage) {
|
|
60591
60607
|
for (const selector of [`[${SECTION_ROOT_ATTRIBUTE}]`, "body > *"]) {
|
|
60592
|
-
const
|
|
60593
|
-
if (!await
|
|
60594
|
-
const shot = await
|
|
60608
|
+
const target4 = page.locator(selector).first();
|
|
60609
|
+
if (!await target4.count()) continue;
|
|
60610
|
+
const shot = await target4.screenshot({ type: "png", timeout: timeoutMs }).catch(() => null);
|
|
60595
60611
|
if (shot) return shot;
|
|
60596
60612
|
}
|
|
60597
60613
|
}
|
|
@@ -61067,8 +61083,8 @@ async function scrapeLanding(options) {
|
|
|
61067
61083
|
import { existsSync as existsSync9 } from "fs";
|
|
61068
61084
|
import path41 from "path";
|
|
61069
61085
|
var SCRATCH_DIR = ".baker";
|
|
61070
|
-
function isWithin(parent,
|
|
61071
|
-
const relative = path41.relative(parent,
|
|
61086
|
+
function isWithin(parent, target4) {
|
|
61087
|
+
const relative = path41.relative(parent, target4);
|
|
61072
61088
|
return relative === "" || !relative.startsWith("..") && !path41.isAbsolute(relative);
|
|
61073
61089
|
}
|
|
61074
61090
|
function findRepoRoot(from) {
|
|
@@ -61359,8 +61375,8 @@ registerSchema({
|
|
|
61359
61375
|
function buildSearchBody(args5) {
|
|
61360
61376
|
const body = {};
|
|
61361
61377
|
const setList2 = (key, value) => {
|
|
61362
|
-
const
|
|
61363
|
-
if (
|
|
61378
|
+
const list3 = splitList2(value);
|
|
61379
|
+
if (list3) Object.assign(body, { [key]: list3 });
|
|
61364
61380
|
};
|
|
61365
61381
|
if (args5.query) body.query = String(args5.query);
|
|
61366
61382
|
if (args5["similar-to"]) body.similarToSectionId = String(args5["similar-to"]);
|
|
@@ -62135,9 +62151,9 @@ function customEntry(server) {
|
|
|
62135
62151
|
var BROKEN_SERVER_HINT = "A server marked usable=false will NOT answer: its tools are absent from this turn. Say plainly that the tool is not working and relay `problem`; never claim its tools are loading, coming next message, or temporarily unavailable. `problem` names what a person has to fix \u2014 the address, the sign-in, or the key the server was added with \u2014 so pass on that fix and no other: never tell the user to reconnect a server whose `problem` is its address or its key. The user makes the fix in the dashboard (Brain \u2192 Integrations \u2192 MCPs). If `suggestedAddress` is present, that is the address to use.";
|
|
62136
62152
|
var LAST_CHECK_FAILED_HINT = "A server with lastCheck=failed was unreachable or erroring when it was last checked \u2014 that may already have passed, and its tools ARE loaded this turn. Try the tool; if it works, say nothing about the check. If it fails, report `problem` as what happened rather than guessing.";
|
|
62137
62153
|
function parseHeaders(raw, rawArgs) {
|
|
62138
|
-
const
|
|
62154
|
+
const list3 = repeatedValues(rawArgs, "header", raw);
|
|
62139
62155
|
const headers = {};
|
|
62140
|
-
for (const entry of
|
|
62156
|
+
for (const entry of list3) {
|
|
62141
62157
|
const text2 = String(entry);
|
|
62142
62158
|
const sep = text2.indexOf(":") >= 0 && (text2.indexOf(":") < text2.indexOf("=") || text2.indexOf("=") < 0) ? ":" : "=";
|
|
62143
62159
|
const at = text2.indexOf(sep);
|
|
@@ -63306,7 +63322,7 @@ Examples:
|
|
|
63306
63322
|
"no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
|
|
63307
63323
|
},
|
|
63308
63324
|
run: async ({ args: args5 }) => {
|
|
63309
|
-
const
|
|
63325
|
+
const target4 = args5.target;
|
|
63310
63326
|
const location2 = args5.location || void 0;
|
|
63311
63327
|
const language = args5.language || void 0;
|
|
63312
63328
|
const sort = args5.sort || void 0;
|
|
@@ -63316,7 +63332,7 @@ Examples:
|
|
|
63316
63332
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63317
63333
|
try {
|
|
63318
63334
|
const data = await apiPost("/api/research/keywords-for-site", {
|
|
63319
|
-
target:
|
|
63335
|
+
target: target4,
|
|
63320
63336
|
location: location2,
|
|
63321
63337
|
language,
|
|
63322
63338
|
sort,
|
|
@@ -63489,7 +63505,7 @@ Examples:
|
|
|
63489
63505
|
"no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
|
|
63490
63506
|
},
|
|
63491
63507
|
run: async ({ args: args5 }) => {
|
|
63492
|
-
const
|
|
63508
|
+
const target4 = args5.target;
|
|
63493
63509
|
const location2 = args5.location || void 0;
|
|
63494
63510
|
const language = args5.language || void 0;
|
|
63495
63511
|
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
@@ -63497,7 +63513,7 @@ Examples:
|
|
|
63497
63513
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63498
63514
|
try {
|
|
63499
63515
|
const data = await apiPost("/api/research/relevant-pages", {
|
|
63500
|
-
target:
|
|
63516
|
+
target: target4,
|
|
63501
63517
|
location: location2,
|
|
63502
63518
|
language,
|
|
63503
63519
|
limit: limit2,
|
|
@@ -63844,7 +63860,7 @@ function refuseMisusedKinds(kind, args5) {
|
|
|
63844
63860
|
}
|
|
63845
63861
|
}
|
|
63846
63862
|
function refuseStrayFlags(kind, args5) {
|
|
63847
|
-
const allowed = new Set(TRIGGER_TARGETS[kind].map((
|
|
63863
|
+
const allowed = new Set(TRIGGER_TARGETS[kind].map((target4) => TRIGGER_TARGET_FIELDS[target4.field].flag));
|
|
63848
63864
|
const stray = TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag).filter(
|
|
63849
63865
|
(flag3) => !allowed.has(flag3) && flagText(args5, flag3) !== void 0 && !(kind === "experiment.started" && flag3 === "experiment")
|
|
63850
63866
|
);
|
|
@@ -64446,8 +64462,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64446
64462
|
try {
|
|
64447
64463
|
const save = flag3("save");
|
|
64448
64464
|
const publish = flag3("publish");
|
|
64449
|
-
const
|
|
64450
|
-
if ([save, publish,
|
|
64465
|
+
const remove2 = flag3("delete");
|
|
64466
|
+
if ([save, publish, remove2].filter((id) => id.length > 0).length > 1) {
|
|
64451
64467
|
failValidation4("Pass one of --save, --publish or --delete at a time.");
|
|
64452
64468
|
}
|
|
64453
64469
|
if (save.length > 0) {
|
|
@@ -64476,10 +64492,10 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64476
64492
|
writeJson(response2);
|
|
64477
64493
|
return;
|
|
64478
64494
|
}
|
|
64479
|
-
if (
|
|
64495
|
+
if (remove2.length > 0) {
|
|
64480
64496
|
const response2 = await apiPost("/api/marketplace/remove", {
|
|
64481
64497
|
chatId: requireChatId(),
|
|
64482
|
-
slug:
|
|
64498
|
+
slug: remove2
|
|
64483
64499
|
});
|
|
64484
64500
|
writeJson(response2);
|
|
64485
64501
|
return;
|
|
@@ -64777,7 +64793,7 @@ var schemaCommand2 = defineCommand208({
|
|
|
64777
64793
|
});
|
|
64778
64794
|
|
|
64779
64795
|
// src/commands/shopify/index.ts
|
|
64780
|
-
import { defineCommand as
|
|
64796
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
64781
64797
|
|
|
64782
64798
|
// src/commands/shopify/buyers.ts
|
|
64783
64799
|
import { defineCommand as defineCommand209 } from "citty";
|
|
@@ -65064,7 +65080,18 @@ var shopifyStoreSummarySchema = z50.object({
|
|
|
65064
65080
|
});
|
|
65065
65081
|
var shopifyStoreResponseSchema = z50.object({
|
|
65066
65082
|
store: shopifyStoreStateSchema,
|
|
65067
|
-
summary: shopifyStoreSummarySchema
|
|
65083
|
+
summary: shopifyStoreSummarySchema,
|
|
65084
|
+
/**
|
|
65085
|
+
* Which store changes Baker may make (S9), by what the store allowed: false
|
|
65086
|
+
* means `baker shopify change …` will ask the user to allow it first.
|
|
65087
|
+
*/
|
|
65088
|
+
canChange: z50.object({
|
|
65089
|
+
products: z50.boolean(),
|
|
65090
|
+
publishing: z50.boolean(),
|
|
65091
|
+
discounts: z50.boolean(),
|
|
65092
|
+
redirects: z50.boolean(),
|
|
65093
|
+
marketing: z50.boolean()
|
|
65094
|
+
}).optional()
|
|
65068
65095
|
});
|
|
65069
65096
|
var shopifyProductRowSchema = z50.object({
|
|
65070
65097
|
productId: z50.string(),
|
|
@@ -65781,6 +65808,323 @@ var shopifyCohortsResponseSchema = z51.object({
|
|
|
65781
65808
|
cohorts: z51.array(shopifyCohortSchema)
|
|
65782
65809
|
});
|
|
65783
65810
|
|
|
65811
|
+
// ../api/src/shopify/writes.ts
|
|
65812
|
+
import { z as z52 } from "zod";
|
|
65813
|
+
var SHOPIFY_TEMP_REF_PREFIX = "shopify_temp_";
|
|
65814
|
+
var SHOPIFY_PERMISSION_NEEDED_PREFIX = "Baker isn't allowed to change this Shopify store yet";
|
|
65815
|
+
var shopifyWriteEntitySchema = z52.enum([
|
|
65816
|
+
"product",
|
|
65817
|
+
"variant",
|
|
65818
|
+
"metafield",
|
|
65819
|
+
"collection",
|
|
65820
|
+
"discountCode",
|
|
65821
|
+
"urlRedirect",
|
|
65822
|
+
"marketingActivity",
|
|
65823
|
+
"webPixel"
|
|
65824
|
+
]);
|
|
65825
|
+
var shopifyDraftOpKindSchema = z52.enum([
|
|
65826
|
+
"shopify.product.update",
|
|
65827
|
+
"shopify.variant.update",
|
|
65828
|
+
"shopify.metafield.set",
|
|
65829
|
+
"shopify.metafield.delete",
|
|
65830
|
+
"shopify.collection.create",
|
|
65831
|
+
"shopify.collection.publish",
|
|
65832
|
+
"shopify.collection.unpublish",
|
|
65833
|
+
"shopify.collection.update",
|
|
65834
|
+
"shopify.collection.delete",
|
|
65835
|
+
"shopify.collection.addProducts",
|
|
65836
|
+
"shopify.collection.removeProducts",
|
|
65837
|
+
"shopify.discountCode.create",
|
|
65838
|
+
"shopify.discountCode.deactivate",
|
|
65839
|
+
"shopify.discountCode.schedule",
|
|
65840
|
+
"shopify.urlRedirect.create",
|
|
65841
|
+
"shopify.urlRedirect.delete",
|
|
65842
|
+
"shopify.marketingActivity.upsert",
|
|
65843
|
+
"shopify.marketingActivity.delete",
|
|
65844
|
+
"shopify.webPixel.update"
|
|
65845
|
+
]);
|
|
65846
|
+
var shopifyDecimalSchema = z52.string().regex(/^\d{1,12}(\.\d{1,4})?$/, 'write amounts as a decimal string, e.g. "19.95"');
|
|
65847
|
+
var tagSchema = z52.string().trim().min(1).max(255);
|
|
65848
|
+
var seoSchema = z52.object({ title: z52.string().max(255).optional(), description: z52.string().max(320).optional() }).strict();
|
|
65849
|
+
var SHOPIFY_DESCRIPTION_MAX_CHARS = 2e5;
|
|
65850
|
+
var descriptionHtmlSchema = z52.string().max(SHOPIFY_DESCRIPTION_MAX_CHARS);
|
|
65851
|
+
var productUpdateSchema = z52.object({
|
|
65852
|
+
title: z52.string().trim().min(1).max(255).optional(),
|
|
65853
|
+
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
65854
|
+
seo: seoSchema.optional(),
|
|
65855
|
+
/** The WHOLE tag list after the change (Shopify replaces it). `addTags`/`removeTags` are resolved against the live tags. */
|
|
65856
|
+
tags: z52.array(tagSchema).max(250).optional(),
|
|
65857
|
+
addTags: z52.array(tagSchema).max(250).optional(),
|
|
65858
|
+
removeTags: z52.array(tagSchema).max(250).optional(),
|
|
65859
|
+
productType: z52.string().max(255).optional()
|
|
65860
|
+
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change").refine(
|
|
65861
|
+
(payload) => payload.tags === void 0 || payload.addTags === void 0 && payload.removeTags === void 0,
|
|
65862
|
+
"give either the whole `tags` list or `addTags`/`removeTags`, not both"
|
|
65863
|
+
);
|
|
65864
|
+
var shopifyWeightUnitSchema = z52.enum(["GRAMS", "KILOGRAMS", "OUNCES", "POUNDS"]);
|
|
65865
|
+
var variantUpdateSchema = z52.object({
|
|
65866
|
+
barcode: z52.string().trim().max(255).optional(),
|
|
65867
|
+
sku: z52.string().trim().max(255).optional(),
|
|
65868
|
+
weight: z52.object({ value: z52.number().nonnegative(), unit: shopifyWeightUnitSchema }).strict().optional(),
|
|
65869
|
+
price: shopifyDecimalSchema.optional(),
|
|
65870
|
+
/** `null` clears the sale ("compare at") price. */
|
|
65871
|
+
compareAtPrice: shopifyDecimalSchema.nullable().optional()
|
|
65872
|
+
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change");
|
|
65873
|
+
var metafieldKeySchema = z52.string().min(2).max(64).regex(/^[A-Za-z0-9_-]+$/, "letters, digits, `_` and `-` only");
|
|
65874
|
+
var metafieldNamespaceSchema = z52.string().min(2).max(255).regex(/^[A-Za-z0-9_-]+$/, "letters, digits, `_` and `-` only");
|
|
65875
|
+
var metafieldSetSchema = z52.object({
|
|
65876
|
+
namespace: metafieldNamespaceSchema,
|
|
65877
|
+
key: metafieldKeySchema,
|
|
65878
|
+
/** Shopify's metafield type, e.g. `single_line_text_field`, `multi_line_text_field`, `rich_text_field`, `number_integer`, `boolean`, `json`. */
|
|
65879
|
+
type: z52.string().min(1).max(100),
|
|
65880
|
+
value: z52.string().max(1e5)
|
|
65881
|
+
}).strict();
|
|
65882
|
+
var metafieldDeleteSchema = z52.object({ namespace: metafieldNamespaceSchema, key: metafieldKeySchema }).strict();
|
|
65883
|
+
var shopifyCollectionSortOrderSchema = z52.enum([
|
|
65884
|
+
"MANUAL",
|
|
65885
|
+
"BEST_SELLING",
|
|
65886
|
+
"ALPHA_ASC",
|
|
65887
|
+
"ALPHA_DESC",
|
|
65888
|
+
"PRICE_DESC",
|
|
65889
|
+
"PRICE_ASC",
|
|
65890
|
+
"CREATED",
|
|
65891
|
+
"CREATED_DESC"
|
|
65892
|
+
]);
|
|
65893
|
+
var handleSchema = z52.string().min(1).max(255).regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/, "lowercase letters, digits and single dashes, e.g. summer-snowboards");
|
|
65894
|
+
var SHOPIFY_COLLECTION_PRODUCTS_MAX = 250;
|
|
65895
|
+
var collectionCreateSchema = z52.object({
|
|
65896
|
+
title: z52.string().trim().min(1).max(255),
|
|
65897
|
+
handle: handleSchema.optional(),
|
|
65898
|
+
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
65899
|
+
seo: seoSchema.optional(),
|
|
65900
|
+
sortOrder: shopifyCollectionSortOrderSchema.optional(),
|
|
65901
|
+
/** The theme template the collection page uses (the part after `collection.`). Kept when a deleted collection is put back. */
|
|
65902
|
+
templateSuffix: z52.string().max(255).optional(),
|
|
65903
|
+
/** Product ids, handles or links, in the order shown with sort order MANUAL. */
|
|
65904
|
+
products: z52.array(z52.string().min(1)).max(SHOPIFY_COLLECTION_PRODUCTS_MAX).optional(),
|
|
65905
|
+
/** Show it on the online store (a second change, staged with it). Default true. */
|
|
65906
|
+
onlineStore: z52.boolean().optional()
|
|
65907
|
+
}).strict();
|
|
65908
|
+
var collectionUpdateSchema = z52.object({
|
|
65909
|
+
title: z52.string().trim().min(1).max(255).optional(),
|
|
65910
|
+
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
65911
|
+
seo: seoSchema.optional(),
|
|
65912
|
+
sortOrder: shopifyCollectionSortOrderSchema.optional()
|
|
65913
|
+
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change");
|
|
65914
|
+
var collectionProductsSchema = z52.object({ products: z52.array(z52.string().min(1)).min(1).max(SHOPIFY_COLLECTION_PRODUCTS_MAX) }).strict();
|
|
65915
|
+
var isoDateTimeSchema = z52.iso.datetime({ offset: true });
|
|
65916
|
+
var discountCodeSchema = z52.string().regex(/^[A-Za-z0-9_-]{3,64}$/, "3\u201364 letters, digits, `_` or `-`, e.g. SPRING10");
|
|
65917
|
+
var discountValueSchema = z52.union([
|
|
65918
|
+
z52.object({ percentage: z52.number().min(1).max(100) }).strict(),
|
|
65919
|
+
z52.object({ amount: shopifyDecimalSchema }).strict()
|
|
65920
|
+
]);
|
|
65921
|
+
var discountAppliesToSchema = z52.union([
|
|
65922
|
+
z52.object({ all: z52.literal(true) }).strict(),
|
|
65923
|
+
z52.object({ products: z52.array(z52.string().min(1)).min(1).max(100) }).strict(),
|
|
65924
|
+
z52.object({ collections: z52.array(z52.string().min(1)).min(1).max(100) }).strict()
|
|
65925
|
+
]);
|
|
65926
|
+
var discountCreateSchema = z52.object({
|
|
65927
|
+
code: discountCodeSchema,
|
|
65928
|
+
/** What the store's staff see; defaults to the code. */
|
|
65929
|
+
title: z52.string().trim().min(1).max(255).optional(),
|
|
65930
|
+
value: discountValueSchema,
|
|
65931
|
+
appliesTo: discountAppliesToSchema,
|
|
65932
|
+
minimumSubtotal: shopifyDecimalSchema.optional(),
|
|
65933
|
+
minimumQuantity: z52.number().int().min(1).max(1e4).optional(),
|
|
65934
|
+
/** Default: the moment it is published. */
|
|
65935
|
+
startsAt: isoDateTimeSchema.optional(),
|
|
65936
|
+
endsAt: isoDateTimeSchema.optional(),
|
|
65937
|
+
usageLimit: z52.number().int().min(1).max(1e6).optional(),
|
|
65938
|
+
/** Default true. */
|
|
65939
|
+
oncePerCustomer: z52.boolean().optional(),
|
|
65940
|
+
combinesWith: z52.object({
|
|
65941
|
+
productDiscounts: z52.boolean().optional(),
|
|
65942
|
+
orderDiscounts: z52.boolean().optional(),
|
|
65943
|
+
shippingDiscounts: z52.boolean().optional()
|
|
65944
|
+
}).strict().optional()
|
|
65945
|
+
}).strict().refine(
|
|
65946
|
+
(payload) => payload.minimumSubtotal === void 0 || payload.minimumQuantity === void 0,
|
|
65947
|
+
"a discount takes a minimum amount or a minimum quantity, not both"
|
|
65948
|
+
);
|
|
65949
|
+
var discountScheduleSchema = z52.object({ startsAt: isoDateTimeSchema, endsAt: isoDateTimeSchema.nullable() }).strict();
|
|
65950
|
+
var storePathSchema = z52.string().min(2).max(1024).regex(/^\/[^\s]*$/, 'a path on the store starting with "/", e.g. /collections/old');
|
|
65951
|
+
var urlRedirectCreateSchema = z52.object({
|
|
65952
|
+
from: storePathSchema,
|
|
65953
|
+
to: z52.union([storePathSchema, z52.url({ protocol: /^https$/ })])
|
|
65954
|
+
}).strict();
|
|
65955
|
+
var shopifyMarketingPlatformSchema = z52.enum(["google-ads", "meta"]);
|
|
65956
|
+
var marketingUpsertSchema = z52.object({
|
|
65957
|
+
platform: shopifyMarketingPlatformSchema,
|
|
65958
|
+
accountId: z52.string().min(1).max(64),
|
|
65959
|
+
campaignId: z52.string().regex(/^\d+$/, "the campaign's numeric id"),
|
|
65960
|
+
utm: z52.object({
|
|
65961
|
+
campaign: z52.string().trim().min(1).max(255),
|
|
65962
|
+
source: z52.string().trim().min(1).max(255),
|
|
65963
|
+
medium: z52.string().trim().min(1).max(255)
|
|
65964
|
+
}).strict()
|
|
65965
|
+
}).strict();
|
|
65966
|
+
var emptySchema = z52.object({}).strict();
|
|
65967
|
+
var opFields = {
|
|
65968
|
+
/** Optional caller-chosen ref for a create, so later ops in the batch can name it (`shopify_temp_…`). */
|
|
65969
|
+
ref: z52.string().startsWith(SHOPIFY_TEMP_REF_PREFIX).max(80).optional()
|
|
65970
|
+
};
|
|
65971
|
+
var target2 = z52.string().trim().min(1).max(2048);
|
|
65972
|
+
var shopifyDraftOpInputSchema = z52.discriminatedUnion("kind", [
|
|
65973
|
+
z52.object({ kind: z52.literal("shopify.product.update"), target: target2, payload: productUpdateSchema, ...opFields }),
|
|
65974
|
+
z52.object({ kind: z52.literal("shopify.variant.update"), target: target2, payload: variantUpdateSchema, ...opFields }),
|
|
65975
|
+
z52.object({ kind: z52.literal("shopify.metafield.set"), target: target2, payload: metafieldSetSchema, ...opFields }),
|
|
65976
|
+
z52.object({ kind: z52.literal("shopify.metafield.delete"), target: target2, payload: metafieldDeleteSchema, ...opFields }),
|
|
65977
|
+
z52.object({ kind: z52.literal("shopify.collection.create"), payload: collectionCreateSchema, ...opFields }),
|
|
65978
|
+
z52.object({ kind: z52.literal("shopify.collection.publish"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
65979
|
+
z52.object({ kind: z52.literal("shopify.collection.unpublish"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
65980
|
+
z52.object({ kind: z52.literal("shopify.collection.update"), target: target2, payload: collectionUpdateSchema, ...opFields }),
|
|
65981
|
+
z52.object({ kind: z52.literal("shopify.collection.delete"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
65982
|
+
z52.object({
|
|
65983
|
+
kind: z52.literal("shopify.collection.addProducts"),
|
|
65984
|
+
target: target2,
|
|
65985
|
+
payload: collectionProductsSchema,
|
|
65986
|
+
...opFields
|
|
65987
|
+
}),
|
|
65988
|
+
z52.object({
|
|
65989
|
+
kind: z52.literal("shopify.collection.removeProducts"),
|
|
65990
|
+
target: target2,
|
|
65991
|
+
payload: collectionProductsSchema,
|
|
65992
|
+
...opFields
|
|
65993
|
+
}),
|
|
65994
|
+
z52.object({ kind: z52.literal("shopify.discountCode.create"), payload: discountCreateSchema, ...opFields }),
|
|
65995
|
+
z52.object({
|
|
65996
|
+
kind: z52.literal("shopify.discountCode.deactivate"),
|
|
65997
|
+
target: target2,
|
|
65998
|
+
payload: emptySchema.optional(),
|
|
65999
|
+
...opFields
|
|
66000
|
+
}),
|
|
66001
|
+
z52.object({ kind: z52.literal("shopify.discountCode.schedule"), target: target2, payload: discountScheduleSchema, ...opFields }),
|
|
66002
|
+
z52.object({ kind: z52.literal("shopify.urlRedirect.create"), payload: urlRedirectCreateSchema, ...opFields }),
|
|
66003
|
+
z52.object({ kind: z52.literal("shopify.urlRedirect.delete"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
66004
|
+
z52.object({ kind: z52.literal("shopify.marketingActivity.upsert"), payload: marketingUpsertSchema, ...opFields }),
|
|
66005
|
+
z52.object({
|
|
66006
|
+
kind: z52.literal("shopify.marketingActivity.delete"),
|
|
66007
|
+
target: target2,
|
|
66008
|
+
payload: emptySchema.optional(),
|
|
66009
|
+
...opFields
|
|
66010
|
+
}),
|
|
66011
|
+
z52.object({ kind: z52.literal("shopify.webPixel.update"), payload: emptySchema.optional(), ...opFields })
|
|
66012
|
+
]);
|
|
66013
|
+
var PAYLOAD_KEYS = new Map(
|
|
66014
|
+
shopifyDraftOpInputSchema.options.map((option) => {
|
|
66015
|
+
const payload = option.shape.payload;
|
|
66016
|
+
const object = payload instanceof z52.ZodOptional ? payload.unwrap() : payload;
|
|
66017
|
+
return [option.shape.kind.value, object instanceof z52.ZodObject ? Object.keys(object.shape) : []];
|
|
66018
|
+
})
|
|
66019
|
+
);
|
|
66020
|
+
var askUserQuestionInputSchema = z52.object({
|
|
66021
|
+
questions: z52.array(
|
|
66022
|
+
z52.object({
|
|
66023
|
+
question: z52.string(),
|
|
66024
|
+
header: z52.string(),
|
|
66025
|
+
multiSelect: z52.boolean(),
|
|
66026
|
+
options: z52.array(z52.object({ label: z52.string(), description: z52.string() })).min(2)
|
|
66027
|
+
})
|
|
66028
|
+
).min(1)
|
|
66029
|
+
});
|
|
66030
|
+
var shopifyNeedsApprovalSchema = z52.object({
|
|
66031
|
+
/** Pass to AskUserQuestion exactly as given. */
|
|
66032
|
+
askUserQuestion: askUserQuestionInputSchema,
|
|
66033
|
+
/** The user already said no to (at least one of) these changes: don't ask again in this turn. */
|
|
66034
|
+
declined: z52.boolean()
|
|
66035
|
+
});
|
|
66036
|
+
var shopifyVerificationSchema = z52.object({
|
|
66037
|
+
status: z52.enum(["confirmed", "drifted", "unconfirmed"]),
|
|
66038
|
+
checkedAt: z52.number(),
|
|
66039
|
+
note: z52.string().optional()
|
|
66040
|
+
});
|
|
66041
|
+
var shopifyDraftOpResultSchema = z52.object({
|
|
66042
|
+
status: z52.enum(["applied", "failed", "skipped"]),
|
|
66043
|
+
createdId: z52.string().optional(),
|
|
66044
|
+
error: z52.string().optional(),
|
|
66045
|
+
note: z52.string().optional(),
|
|
66046
|
+
skippedBecause: z52.string().optional(),
|
|
66047
|
+
executedAt: z52.number().optional(),
|
|
66048
|
+
pendingJob: z52.string().optional(),
|
|
66049
|
+
verification: shopifyVerificationSchema.optional()
|
|
66050
|
+
});
|
|
66051
|
+
var stagedOpSchema = z52.object({
|
|
66052
|
+
ref: z52.string(),
|
|
66053
|
+
kind: shopifyDraftOpKindSchema,
|
|
66054
|
+
summary: z52.string(),
|
|
66055
|
+
warnings: z52.array(z52.string())
|
|
66056
|
+
});
|
|
66057
|
+
var shopifyDraftStageResponseSchema = z52.union([
|
|
66058
|
+
z52.object({
|
|
66059
|
+
staged: z52.literal(true),
|
|
66060
|
+
count: z52.number(),
|
|
66061
|
+
ops: z52.array(stagedOpSchema),
|
|
66062
|
+
amended: z52.boolean().optional()
|
|
66063
|
+
}),
|
|
66064
|
+
z52.object({ staged: z52.literal(false), needsApproval: shopifyNeedsApprovalSchema })
|
|
66065
|
+
]);
|
|
66066
|
+
var SHOPIFY_DRAFT_BATCH_MAX = 100;
|
|
66067
|
+
var shopifyDraftStageRequestSchema = z52.object({ chatId: z52.string(), op: shopifyDraftOpInputSchema });
|
|
66068
|
+
var shopifyDraftStageBatchRequestSchema = z52.object({
|
|
66069
|
+
chatId: z52.string(),
|
|
66070
|
+
ops: z52.array(shopifyDraftOpInputSchema).min(1).max(SHOPIFY_DRAFT_BATCH_MAX)
|
|
66071
|
+
});
|
|
66072
|
+
var shopifyDraftAmendRequestSchema = z52.object({
|
|
66073
|
+
chatId: z52.string(),
|
|
66074
|
+
ref: z52.string(),
|
|
66075
|
+
patch: z52.record(z52.string(), z52.unknown())
|
|
66076
|
+
});
|
|
66077
|
+
var shopifyDraftOpViewSchema = z52.object({
|
|
66078
|
+
ref: z52.string(),
|
|
66079
|
+
kind: shopifyDraftOpKindSchema,
|
|
66080
|
+
entity: shopifyWriteEntitySchema,
|
|
66081
|
+
target: z52.string().optional(),
|
|
66082
|
+
targetLabel: z52.string().optional(),
|
|
66083
|
+
summary: z52.string(),
|
|
66084
|
+
money: z52.boolean(),
|
|
66085
|
+
warnings: z52.array(z52.string()).optional(),
|
|
66086
|
+
dependsOn: z52.array(z52.string()),
|
|
66087
|
+
undoOf: z52.string().optional(),
|
|
66088
|
+
stagedAt: z52.number(),
|
|
66089
|
+
result: shopifyDraftOpResultSchema.optional()
|
|
66090
|
+
});
|
|
66091
|
+
var shopifyDraftListRequestSchema = z52.object({ chatId: z52.string() });
|
|
66092
|
+
var shopifyDraftListResponseSchema = z52.object({
|
|
66093
|
+
status: z52.enum(["active", "publishing", "applied", "discarded", "none"]),
|
|
66094
|
+
store: z52.string().optional(),
|
|
66095
|
+
count: z52.number(),
|
|
66096
|
+
ops: z52.array(shopifyDraftOpViewSchema),
|
|
66097
|
+
publishError: z52.string().optional()
|
|
66098
|
+
});
|
|
66099
|
+
var shopifyDraftShowRequestSchema = z52.object({ chatId: z52.string(), ref: z52.string() });
|
|
66100
|
+
var shopifyDraftShowResponseSchema = z52.object({
|
|
66101
|
+
op: shopifyDraftOpViewSchema.extend({ payload: z52.unknown().optional(), before: z52.unknown().optional() })
|
|
66102
|
+
});
|
|
66103
|
+
var shopifyDraftRemoveRequestSchema = z52.object({ chatId: z52.string(), ref: z52.string() });
|
|
66104
|
+
var shopifyDraftRemoveResponseSchema = z52.object({ removed: z52.array(z52.string()) });
|
|
66105
|
+
var shopifyDraftClearRequestSchema = z52.object({ chatId: z52.string() });
|
|
66106
|
+
var shopifyDraftClearResponseSchema = z52.object({ cleared: z52.number() });
|
|
66107
|
+
var shopifyChangeViewSchema = z52.object({
|
|
66108
|
+
changeId: z52.string(),
|
|
66109
|
+
when: z52.string(),
|
|
66110
|
+
kind: shopifyDraftOpKindSchema,
|
|
66111
|
+
summary: z52.string(),
|
|
66112
|
+
status: z52.enum(["applied", "failed", "undone"]),
|
|
66113
|
+
chatId: z52.string(),
|
|
66114
|
+
undoable: z52.boolean(),
|
|
66115
|
+
/** Why it can't be undone, when it can't. Whether the store still holds Baker's change is checked when undo is staged. */
|
|
66116
|
+
notUndoableBecause: z52.string().optional()
|
|
66117
|
+
});
|
|
66118
|
+
var shopifyChangesRequestSchema = z52.object({
|
|
66119
|
+
limit: z52.coerce.number().int().min(1).max(100).optional(),
|
|
66120
|
+
chatId: z52.string().optional()
|
|
66121
|
+
});
|
|
66122
|
+
var shopifyChangesResponseSchema = z52.object({ changes: z52.array(shopifyChangeViewSchema) });
|
|
66123
|
+
var shopifyUndoRequestSchema = z52.object({
|
|
66124
|
+
chatId: z52.string(),
|
|
66125
|
+
changeIds: z52.array(z52.string().min(1)).min(1).max(SHOPIFY_DRAFT_BATCH_MAX)
|
|
66126
|
+
});
|
|
66127
|
+
|
|
65784
66128
|
// src/commands/shopify/refusal.ts
|
|
65785
66129
|
var CONTINUE2 = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else.";
|
|
65786
66130
|
function shopifyRefusal(code, message) {
|
|
@@ -65805,6 +66149,36 @@ function shopifyRefusal(code, message) {
|
|
|
65805
66149
|
}
|
|
65806
66150
|
return null;
|
|
65807
66151
|
}
|
|
66152
|
+
function storeChangeRefusal(code, message) {
|
|
66153
|
+
if (code !== "FORBIDDEN" || !message.startsWith(SHOPIFY_PERMISSION_NEEDED_PREFIX)) return null;
|
|
66154
|
+
return {
|
|
66155
|
+
code: "SHOPIFY_PERMISSION_NEEDED",
|
|
66156
|
+
fix: {
|
|
66157
|
+
action: "request_connection",
|
|
66158
|
+
explanation: 'AGENT INSTRUCTION: the store hasn\'t allowed Baker to make this kind of change yet, and only the user can. Call `request_connection` with { platform: "shopify", reason } \u2014 reason in their words, e.g. "so I can update your product titles". They allow it in Shopify; the card finishes when Shopify confirms. If its result lists something under cannotRead, that change is still not allowed: don\'t promise it. Then run this command again. Keep going with the rest of the task.'
|
|
66159
|
+
}
|
|
66160
|
+
};
|
|
66161
|
+
}
|
|
66162
|
+
function approvalRefusal(needsApproval) {
|
|
66163
|
+
if (needsApproval.declined) {
|
|
66164
|
+
return {
|
|
66165
|
+
code: "NEEDS_USER_APPROVAL",
|
|
66166
|
+
fix: {
|
|
66167
|
+
action: "continue_without",
|
|
66168
|
+
askUserQuestion: needsApproval.askUserQuestion,
|
|
66169
|
+
explanation: "The user said no to this change. Don't stage it, don't ask again on your own, and don't find another way to make it; carry on with the rest of the task. Ask again only if the user asks for it again (they changed their mind): then call AskUserQuestion with `askUserQuestion` exactly as given, and if they choose \"Yes, make these changes\", run this same command again."
|
|
66170
|
+
}
|
|
66171
|
+
};
|
|
66172
|
+
}
|
|
66173
|
+
return {
|
|
66174
|
+
code: "NEEDS_USER_APPROVAL",
|
|
66175
|
+
fix: {
|
|
66176
|
+
action: "ask_user",
|
|
66177
|
+
askUserQuestion: needsApproval.askUserQuestion,
|
|
66178
|
+
explanation: 'This changes money in the store, so the user says yes first. Call AskUserQuestion with `askUserQuestion` exactly as given (you may say a sentence before it, never change it). If the user chooses "Yes, make these changes", run this same command again. Do not stage it any other way.'
|
|
66179
|
+
}
|
|
66180
|
+
};
|
|
66181
|
+
}
|
|
65808
66182
|
|
|
65809
66183
|
// src/commands/shopify/common.ts
|
|
65810
66184
|
var PRODUCT_NOT_FOUND_HINT = "Find it with `baker shopify products --search <words>`. If `baker shopify store` shows products Baker couldn't read or products still coming in, it may be one of those \u2014 say so rather than that it doesn't exist.";
|
|
@@ -66425,9 +66799,771 @@ var segmentsCommand = defineCommand209({
|
|
|
66425
66799
|
}
|
|
66426
66800
|
});
|
|
66427
66801
|
|
|
66428
|
-
// src/commands/shopify/
|
|
66802
|
+
// src/commands/shopify/change.ts
|
|
66803
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
66804
|
+
|
|
66805
|
+
// src/commands/shopify/writeCommon.ts
|
|
66429
66806
|
import { defineCommand as defineCommand210 } from "citty";
|
|
66430
66807
|
|
|
66808
|
+
// src/commands/shopify/writeHints.ts
|
|
66809
|
+
var STAGED = "Staged \u2014 nothing changes in the store until the user publishes the chat. Review: `baker shopify draft list`. Say the change is ready and happens when they publish, never that it is done.";
|
|
66810
|
+
var WARNINGS = "Read the warnings above before telling the user this is ready.";
|
|
66811
|
+
var DISCOUNT = "The code works only after the chat is published; don't announce it as live or share it as working yet.";
|
|
66812
|
+
var EMPTY_COLLECTION = "The new collection has no products yet: add them with `baker shopify change collection add <collection> <product\u2026>`.";
|
|
66813
|
+
var COLLECTION_DELETE = "Its address stops working when it is deleted: keep old links alive with `baker shopify change redirect create --from /collections/<handle> --to <page>` (ask the user where they should land).";
|
|
66814
|
+
function stageHints(data) {
|
|
66815
|
+
if (!data.staged) return [];
|
|
66816
|
+
const hints2 = [STAGED];
|
|
66817
|
+
if (data.ops.some((op) => op.warnings.length > 0)) hints2.push(WARNINGS);
|
|
66818
|
+
if (data.ops.some((op) => op.kind === "shopify.discountCode.create")) hints2.push(DISCOUNT);
|
|
66819
|
+
if (data.ops.some((op) => op.kind === "shopify.collection.delete")) hints2.push(COLLECTION_DELETE);
|
|
66820
|
+
if (data.ops.some(
|
|
66821
|
+
(op) => op.kind === "shopify.collection.create" && op.warnings.some((warning) => /no products/.test(warning))
|
|
66822
|
+
)) {
|
|
66823
|
+
hints2.push(EMPTY_COLLECTION);
|
|
66824
|
+
}
|
|
66825
|
+
return hints2;
|
|
66826
|
+
}
|
|
66827
|
+
function changesHints(data) {
|
|
66828
|
+
if (data.changes.length === 0) return ["Baker hasn't changed this store yet."];
|
|
66829
|
+
return data.changes.some((change) => change.undoable) ? ["Undo one with `baker shopify undo <changeId>` (staged like any change, applied when the user publishes)."] : [];
|
|
66830
|
+
}
|
|
66831
|
+
function auditHints(data) {
|
|
66832
|
+
const hints2 = [];
|
|
66833
|
+
for (const check of data.checks) {
|
|
66834
|
+
if (check.fix?.kind === "staged") hints2.push(`Stage the fix for "${check.title}": \`${check.fix.command}\`.`);
|
|
66835
|
+
}
|
|
66836
|
+
for (const check of data.checks) {
|
|
66837
|
+
if (check.fix?.kind === "merchant") {
|
|
66838
|
+
hints2.push(
|
|
66839
|
+
`Only the merchant can fix "${check.title}": ${check.fix.task}. Make it a Task with \`baker actions create\`${check.fix.link ? " and include the link" : ""}.`
|
|
66840
|
+
);
|
|
66841
|
+
}
|
|
66842
|
+
}
|
|
66843
|
+
for (const check of data.checks) {
|
|
66844
|
+
if (check.fix?.kind === "decision") hints2.push(`A person decides "${check.title}": ${check.fix.where}.`);
|
|
66845
|
+
}
|
|
66846
|
+
return hints2;
|
|
66847
|
+
}
|
|
66848
|
+
|
|
66849
|
+
// src/commands/shopify/writeCommon.ts
|
|
66850
|
+
function failChange(err) {
|
|
66851
|
+
if (err instanceof ApiError) {
|
|
66852
|
+
const refusal = storeChangeRefusal(err.code, err.message);
|
|
66853
|
+
if (refusal) {
|
|
66854
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
66855
|
+
process.exit(1);
|
|
66856
|
+
}
|
|
66857
|
+
}
|
|
66858
|
+
fail9(err);
|
|
66859
|
+
}
|
|
66860
|
+
function emitStage(data) {
|
|
66861
|
+
if (!data.staged) {
|
|
66862
|
+
const refusal = approvalRefusal(data.needsApproval);
|
|
66863
|
+
writeJson({
|
|
66864
|
+
ok: false,
|
|
66865
|
+
error: {
|
|
66866
|
+
code: refusal.code,
|
|
66867
|
+
message: data.needsApproval.declined ? "The user said no to this change in the chat." : "This changes money in the store: the user has to say yes to it in the chat first.",
|
|
66868
|
+
fix: refusal.fix
|
|
66869
|
+
}
|
|
66870
|
+
});
|
|
66871
|
+
process.exit(1);
|
|
66872
|
+
}
|
|
66873
|
+
writeJson({ ok: true, hints: stageHints(data), data });
|
|
66874
|
+
}
|
|
66875
|
+
async function stage(ops) {
|
|
66876
|
+
const chatId = requireChatId();
|
|
66877
|
+
try {
|
|
66878
|
+
const [only] = ops;
|
|
66879
|
+
const data = ops.length === 1 && only ? await apiPost("/api/shopify/draft/stage", { chatId, op: only }) : await apiPost("/api/shopify/draft/stage-batch", { chatId, ops });
|
|
66880
|
+
emitStage(data);
|
|
66881
|
+
} catch (err) {
|
|
66882
|
+
failChange(err);
|
|
66883
|
+
}
|
|
66884
|
+
}
|
|
66885
|
+
function list(value) {
|
|
66886
|
+
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
66887
|
+
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
66888
|
+
}
|
|
66889
|
+
function defined(entries) {
|
|
66890
|
+
return Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== void 0 && value !== ""));
|
|
66891
|
+
}
|
|
66892
|
+
function payloadsFrom(args5) {
|
|
66893
|
+
if (typeof args5.json !== "string" && typeof args5.file !== "string") return null;
|
|
66894
|
+
return loadJsonPayloads(args5);
|
|
66895
|
+
}
|
|
66896
|
+
var JSON_ARGS = {
|
|
66897
|
+
json: {
|
|
66898
|
+
type: "string",
|
|
66899
|
+
description: 'The change as inline JSON: a payload for the target given (e.g. {"addTags":["summer"]}), or an array of {"kind","target","payload"} items to stage together in one store read',
|
|
66900
|
+
required: false
|
|
66901
|
+
},
|
|
66902
|
+
file: { type: "string", description: "A JSON file holding the same", required: false }
|
|
66903
|
+
};
|
|
66904
|
+
function leaf(schemaName, meta, args5, run) {
|
|
66905
|
+
registerSchema({
|
|
66906
|
+
command: schemaName,
|
|
66907
|
+
description: meta.description,
|
|
66908
|
+
args: Object.fromEntries(
|
|
66909
|
+
Object.entries(args5).map(([name, arg]) => [
|
|
66910
|
+
name,
|
|
66911
|
+
{
|
|
66912
|
+
type: String(arg.type ?? "string"),
|
|
66913
|
+
description: String(arg.description ?? ""),
|
|
66914
|
+
required: arg.required === true
|
|
66915
|
+
}
|
|
66916
|
+
])
|
|
66917
|
+
)
|
|
66918
|
+
});
|
|
66919
|
+
return defineCommand210({ meta, args: args5, run: async ({ args: parsed }) => await run(parsed) });
|
|
66920
|
+
}
|
|
66921
|
+
|
|
66922
|
+
// src/commands/shopify/change.ts
|
|
66923
|
+
var TARGET = (what) => ({ type: "positional", description: what, required: false });
|
|
66924
|
+
function positionals(args5) {
|
|
66925
|
+
return Array.isArray(args5._) ? args5._.filter((value) => typeof value === "string") : [];
|
|
66926
|
+
}
|
|
66927
|
+
function target3(args5, what) {
|
|
66928
|
+
const [first] = positionals(args5);
|
|
66929
|
+
if (!first) failValidation3(`pass the ${what} as the first argument`);
|
|
66930
|
+
return first;
|
|
66931
|
+
}
|
|
66932
|
+
async function stageFor(kind, args5, flags, targetOf) {
|
|
66933
|
+
const payloads = payloadsFrom(args5);
|
|
66934
|
+
if (payloads) {
|
|
66935
|
+
await stage(
|
|
66936
|
+
payloads.map(
|
|
66937
|
+
(payload2) => "kind" in payload2 ? payload2 : { kind, ...targetOf ? { target: targetOf() } : {}, payload: payload2 }
|
|
66938
|
+
)
|
|
66939
|
+
);
|
|
66940
|
+
return;
|
|
66941
|
+
}
|
|
66942
|
+
const payload = flags();
|
|
66943
|
+
if (Object.keys(payload).length === 0)
|
|
66944
|
+
failValidation3("name at least one thing to change (see `baker schema` for the flags)");
|
|
66945
|
+
await stage([{ kind, ...targetOf ? { target: targetOf() } : {}, payload }]);
|
|
66946
|
+
}
|
|
66947
|
+
var productUpdate = leaf(
|
|
66948
|
+
"shopify.change.product.update",
|
|
66949
|
+
{
|
|
66950
|
+
name: "update",
|
|
66951
|
+
description: `Start here to change a product's title, description, SEO, tags or type. Example: baker shopify change product update the-snowboard --title "The Snowboard" --seo-title "\u2026" --add-tags summer. Tags: --tags replaces the whole list, --add-tags/--remove-tags edit it. Descriptions are HTML without scripts or frames. Many products in one call: --json '[{"kind":"shopify.product.update","target":"<handle>","payload":{"addTags":["summer"]}}, \u2026]' \u2014 payload keys: title, descriptionHtml, seo {title, description}, tags | addTags | removeTags, productType.`
|
|
66952
|
+
},
|
|
66953
|
+
{
|
|
66954
|
+
product: TARGET("Product id, handle or link"),
|
|
66955
|
+
title: { type: "string", description: "New title", required: false },
|
|
66956
|
+
description: { type: "string", description: "New description, as HTML (no scripts or frames)", required: false },
|
|
66957
|
+
"seo-title": { type: "string", description: "Title shown in search results", required: false },
|
|
66958
|
+
"seo-description": { type: "string", description: "Description shown in search results", required: false },
|
|
66959
|
+
tags: { type: "string", description: "The whole tag list, comma separated (replaces it)", required: false },
|
|
66960
|
+
"add-tags": { type: "string", description: "Tags to add, comma separated", required: false },
|
|
66961
|
+
"remove-tags": { type: "string", description: "Tags to remove, comma separated", required: false },
|
|
66962
|
+
type: { type: "string", description: "Product type", required: false },
|
|
66963
|
+
...JSON_ARGS
|
|
66964
|
+
},
|
|
66965
|
+
async (args5) => await stageFor(
|
|
66966
|
+
"shopify.product.update",
|
|
66967
|
+
args5,
|
|
66968
|
+
() => defined({
|
|
66969
|
+
title: args5.title,
|
|
66970
|
+
descriptionHtml: args5.description,
|
|
66971
|
+
seo: args5["seo-title"] !== void 0 || args5["seo-description"] !== void 0 ? defined({ title: args5["seo-title"], description: args5["seo-description"] }) : void 0,
|
|
66972
|
+
tags: list(args5.tags),
|
|
66973
|
+
addTags: list(args5["add-tags"]),
|
|
66974
|
+
removeTags: list(args5["remove-tags"]),
|
|
66975
|
+
productType: args5.type
|
|
66976
|
+
}),
|
|
66977
|
+
positionals(args5).length > 0 ? () => target3(args5, "product") : void 0
|
|
66978
|
+
)
|
|
66979
|
+
);
|
|
66980
|
+
var WEIGHT_UNITS = {
|
|
66981
|
+
g: "GRAMS",
|
|
66982
|
+
gram: "GRAMS",
|
|
66983
|
+
grams: "GRAMS",
|
|
66984
|
+
kg: "KILOGRAMS",
|
|
66985
|
+
kgs: "KILOGRAMS",
|
|
66986
|
+
kilogram: "KILOGRAMS",
|
|
66987
|
+
kilograms: "KILOGRAMS",
|
|
66988
|
+
oz: "OUNCES",
|
|
66989
|
+
ounce: "OUNCES",
|
|
66990
|
+
ounces: "OUNCES",
|
|
66991
|
+
lb: "POUNDS",
|
|
66992
|
+
lbs: "POUNDS",
|
|
66993
|
+
pound: "POUNDS",
|
|
66994
|
+
pounds: "POUNDS"
|
|
66995
|
+
};
|
|
66996
|
+
function weightOf(value, unit) {
|
|
66997
|
+
if (value === void 0) return void 0;
|
|
66998
|
+
const named = typeof unit === "string" ? unit.trim() : "";
|
|
66999
|
+
return {
|
|
67000
|
+
value: Number(value),
|
|
67001
|
+
unit: named ? WEIGHT_UNITS[named.toLowerCase()] ?? named.toUpperCase() : "KILOGRAMS"
|
|
67002
|
+
};
|
|
67003
|
+
}
|
|
67004
|
+
var variantUpdate = leaf(
|
|
67005
|
+
"shopify.change.variant.update",
|
|
67006
|
+
{
|
|
67007
|
+
name: "update",
|
|
67008
|
+
description: "Change one option (variant) of a product: SKU, barcode (GTIN), weight \u2014 and its price or sale price, which the user must approve in the chat first (the command hands you the question). Take the option's id from `baker shopify product <product>` (variantId). Example: baker shopify change variant update 456 --sku SNOW-L --barcode 4006381333931 --weight 1.5 --weight-unit kg. --sale-price none clears it."
|
|
67009
|
+
},
|
|
67010
|
+
{
|
|
67011
|
+
variant: TARGET("The option's id (variantId from baker shopify product)"),
|
|
67012
|
+
sku: { type: "string", description: "SKU", required: false },
|
|
67013
|
+
barcode: { type: "string", description: "Barcode / GTIN (8, 12, 13 or 14 digits)", required: false },
|
|
67014
|
+
weight: { type: "string", description: "Weight value", required: false },
|
|
67015
|
+
"weight-unit": {
|
|
67016
|
+
type: "string",
|
|
67017
|
+
description: "kg | g | lb | oz (default kg)",
|
|
67018
|
+
required: false
|
|
67019
|
+
},
|
|
67020
|
+
price: {
|
|
67021
|
+
type: "string",
|
|
67022
|
+
description: `Price as a decimal, e.g. "649.95" (needs the user's yes)`,
|
|
67023
|
+
required: false
|
|
67024
|
+
},
|
|
67025
|
+
"sale-price": {
|
|
67026
|
+
type: "string",
|
|
67027
|
+
description: `Compare-at price, or "none" to clear it (needs the user's yes)`,
|
|
67028
|
+
required: false
|
|
67029
|
+
},
|
|
67030
|
+
...JSON_ARGS
|
|
67031
|
+
},
|
|
67032
|
+
async (args5) => await stageFor(
|
|
67033
|
+
"shopify.variant.update",
|
|
67034
|
+
args5,
|
|
67035
|
+
() => defined({
|
|
67036
|
+
sku: args5.sku,
|
|
67037
|
+
barcode: args5.barcode,
|
|
67038
|
+
weight: weightOf(args5.weight, args5["weight-unit"]),
|
|
67039
|
+
price: args5.price,
|
|
67040
|
+
compareAtPrice: args5["sale-price"] === "none" ? null : args5["sale-price"]
|
|
67041
|
+
}),
|
|
67042
|
+
positionals(args5).length > 0 ? () => target3(args5, "option id") : void 0
|
|
67043
|
+
)
|
|
67044
|
+
);
|
|
67045
|
+
var fieldSet = leaf(
|
|
67046
|
+
"shopify.change.field.set",
|
|
67047
|
+
{
|
|
67048
|
+
name: "set",
|
|
67049
|
+
description: 'Set a custom field (metafield) on a product, an option or a collection. The owner is product:<ref>, variant:<id>, collection:<ref> or a collection staged in this chat (its shopify_temp_ ref); a bare reference is a product. If the store defines the field, send its type. Example: baker shopify change field set product:the-snowboard --namespace custom --key care --type single_line_text_field --value "Wash cold".'
|
|
67050
|
+
},
|
|
67051
|
+
{
|
|
67052
|
+
owner: TARGET("product:<ref>, variant:<id> or collection:<ref>"),
|
|
67053
|
+
namespace: { type: "string", description: "Namespace, e.g. custom", required: false },
|
|
67054
|
+
key: { type: "string", description: "Key, e.g. care", required: false },
|
|
67055
|
+
type: {
|
|
67056
|
+
type: "string",
|
|
67057
|
+
description: "Shopify's type, e.g. single_line_text_field, rich_text_field, json",
|
|
67058
|
+
required: false
|
|
67059
|
+
},
|
|
67060
|
+
value: { type: "string", description: "The value, as Shopify takes it for that type", required: false },
|
|
67061
|
+
...JSON_ARGS
|
|
67062
|
+
},
|
|
67063
|
+
async (args5) => await stageFor(
|
|
67064
|
+
"shopify.metafield.set",
|
|
67065
|
+
args5,
|
|
67066
|
+
() => defined({ namespace: args5.namespace, key: args5.key, type: args5.type, value: args5.value }),
|
|
67067
|
+
() => target3(args5, "owner")
|
|
67068
|
+
)
|
|
67069
|
+
);
|
|
67070
|
+
var fieldRemove = leaf(
|
|
67071
|
+
"shopify.change.field.remove",
|
|
67072
|
+
{
|
|
67073
|
+
name: "remove",
|
|
67074
|
+
description: "Remove a custom field from a product, an option or a collection. Example: baker shopify change field remove product:the-snowboard custom.care"
|
|
67075
|
+
},
|
|
67076
|
+
{
|
|
67077
|
+
owner: TARGET("product:<ref>, variant:<id> or collection:<ref>"),
|
|
67078
|
+
field: TARGET("namespace.key, e.g. custom.care")
|
|
67079
|
+
},
|
|
67080
|
+
async (args5) => {
|
|
67081
|
+
const [owner, field] = positionals(args5);
|
|
67082
|
+
const [namespace, ...rest] = (field ?? "").split(".");
|
|
67083
|
+
if (!owner || !namespace || rest.length === 0) failValidation3("pass the owner and the field as namespace.key");
|
|
67084
|
+
await stage([{ kind: "shopify.metafield.delete", target: owner, payload: { namespace, key: rest.join(".") } }]);
|
|
67085
|
+
}
|
|
67086
|
+
);
|
|
67087
|
+
var collectionCreate = leaf(
|
|
67088
|
+
"shopify.change.collection.create",
|
|
67089
|
+
{
|
|
67090
|
+
name: "create",
|
|
67091
|
+
description: 'Create a collection of hand-picked products, shown on the online store (a second change, staged with it) unless --hidden. Example: baker shopify change collection create --title "Summer boards" --products snowboard-a,snowboard-b. Collections whose products join by rules are made in Shopify.'
|
|
67092
|
+
},
|
|
67093
|
+
{
|
|
67094
|
+
title: { type: "string", description: "Title", required: false },
|
|
67095
|
+
handle: {
|
|
67096
|
+
type: "string",
|
|
67097
|
+
description: "Its address (/collections/<handle>); default from the title",
|
|
67098
|
+
required: false
|
|
67099
|
+
},
|
|
67100
|
+
description: { type: "string", description: "Description, as HTML (no scripts or frames)", required: false },
|
|
67101
|
+
"seo-title": { type: "string", description: "Title shown in search results", required: false },
|
|
67102
|
+
"seo-description": { type: "string", description: "Description shown in search results", required: false },
|
|
67103
|
+
products: {
|
|
67104
|
+
type: "string",
|
|
67105
|
+
description: "Products, comma separated (ids, handles or links), in order",
|
|
67106
|
+
required: false
|
|
67107
|
+
},
|
|
67108
|
+
sort: {
|
|
67109
|
+
type: "string",
|
|
67110
|
+
description: "MANUAL | BEST_SELLING | ALPHA_ASC | ALPHA_DESC | PRICE_ASC | PRICE_DESC | CREATED | CREATED_DESC",
|
|
67111
|
+
required: false
|
|
67112
|
+
},
|
|
67113
|
+
hidden: { type: "boolean", description: "Don't show it on the online store yet", required: false },
|
|
67114
|
+
...JSON_ARGS
|
|
67115
|
+
},
|
|
67116
|
+
async (args5) => await stageFor(
|
|
67117
|
+
"shopify.collection.create",
|
|
67118
|
+
args5,
|
|
67119
|
+
() => defined({
|
|
67120
|
+
title: args5.title,
|
|
67121
|
+
handle: args5.handle,
|
|
67122
|
+
descriptionHtml: args5.description,
|
|
67123
|
+
seo: args5["seo-title"] !== void 0 || args5["seo-description"] !== void 0 ? defined({ title: args5["seo-title"], description: args5["seo-description"] }) : void 0,
|
|
67124
|
+
products: list(args5.products),
|
|
67125
|
+
sortOrder: typeof args5.sort === "string" ? args5.sort.toUpperCase() : void 0,
|
|
67126
|
+
onlineStore: args5.hidden === true ? false : void 0
|
|
67127
|
+
})
|
|
67128
|
+
)
|
|
67129
|
+
);
|
|
67130
|
+
var collectionUpdate = leaf(
|
|
67131
|
+
"shopify.change.collection.update",
|
|
67132
|
+
{
|
|
67133
|
+
name: "update",
|
|
67134
|
+
description: `Change a collection's title, description, SEO or sort order (its address stays: stage a redirect to move it). Example: baker shopify change collection update summer-boards --title "Summer"`
|
|
67135
|
+
},
|
|
67136
|
+
{
|
|
67137
|
+
collection: TARGET("Collection id, handle or link"),
|
|
67138
|
+
title: { type: "string", description: "New title", required: false },
|
|
67139
|
+
description: { type: "string", description: "New description, as HTML", required: false },
|
|
67140
|
+
"seo-title": { type: "string", description: "Title shown in search results", required: false },
|
|
67141
|
+
"seo-description": { type: "string", description: "Description shown in search results", required: false },
|
|
67142
|
+
sort: { type: "string", description: "Sort order (see collection create)", required: false },
|
|
67143
|
+
...JSON_ARGS
|
|
67144
|
+
},
|
|
67145
|
+
async (args5) => await stageFor(
|
|
67146
|
+
"shopify.collection.update",
|
|
67147
|
+
args5,
|
|
67148
|
+
() => defined({
|
|
67149
|
+
title: args5.title,
|
|
67150
|
+
descriptionHtml: args5.description,
|
|
67151
|
+
seo: args5["seo-title"] !== void 0 || args5["seo-description"] !== void 0 ? defined({ title: args5["seo-title"], description: args5["seo-description"] }) : void 0,
|
|
67152
|
+
sortOrder: typeof args5.sort === "string" ? args5.sort.toUpperCase() : void 0
|
|
67153
|
+
}),
|
|
67154
|
+
() => target3(args5, "collection")
|
|
67155
|
+
)
|
|
67156
|
+
);
|
|
67157
|
+
function collectionVerb(verb, kind, description) {
|
|
67158
|
+
return leaf(
|
|
67159
|
+
`shopify.change.collection.${verb}`,
|
|
67160
|
+
{ name: verb, description },
|
|
67161
|
+
{ collection: TARGET("Collection id, handle, link or a shopify_temp_ ref staged in this chat") },
|
|
67162
|
+
async (args5) => await stage([{ kind, target: target3(args5, "collection") }])
|
|
67163
|
+
);
|
|
67164
|
+
}
|
|
67165
|
+
function membership(verb, kind, description) {
|
|
67166
|
+
return leaf(
|
|
67167
|
+
`shopify.change.collection.${verb}`,
|
|
67168
|
+
{ name: verb, description },
|
|
67169
|
+
{
|
|
67170
|
+
collection: TARGET("Collection id, handle, link or a shopify_temp_ ref"),
|
|
67171
|
+
products: TARGET("Products (ids, handles or links), space separated")
|
|
67172
|
+
},
|
|
67173
|
+
async (args5) => {
|
|
67174
|
+
const [collection, ...products] = positionals(args5);
|
|
67175
|
+
if (!collection || products.length === 0) failValidation3("pass the collection, then the products");
|
|
67176
|
+
await stage([{ kind, target: collection, payload: { products } }]);
|
|
67177
|
+
}
|
|
67178
|
+
);
|
|
67179
|
+
}
|
|
67180
|
+
function discountValue(args5) {
|
|
67181
|
+
if (args5.percent !== void 0) return { percentage: Number(args5.percent) };
|
|
67182
|
+
if (args5.amount !== void 0) return { amount: args5.amount };
|
|
67183
|
+
return void 0;
|
|
67184
|
+
}
|
|
67185
|
+
function appliesToOf(args5) {
|
|
67186
|
+
const products = list(args5.products);
|
|
67187
|
+
if (products) return { products };
|
|
67188
|
+
const collections = list(args5.collections);
|
|
67189
|
+
return collections ? { collections } : { all: true };
|
|
67190
|
+
}
|
|
67191
|
+
function combinesOf(value) {
|
|
67192
|
+
const combines = list(value) ?? [];
|
|
67193
|
+
if (combines.length === 0) return void 0;
|
|
67194
|
+
return {
|
|
67195
|
+
productDiscounts: combines.includes("product"),
|
|
67196
|
+
orderDiscounts: combines.includes("order"),
|
|
67197
|
+
shippingDiscounts: combines.includes("shipping")
|
|
67198
|
+
};
|
|
67199
|
+
}
|
|
67200
|
+
function numberOf3(value) {
|
|
67201
|
+
return value === void 0 ? void 0 : Number(value);
|
|
67202
|
+
}
|
|
67203
|
+
function discountPayload(args5) {
|
|
67204
|
+
return defined({
|
|
67205
|
+
code: args5.code,
|
|
67206
|
+
title: args5.title,
|
|
67207
|
+
value: discountValue(args5),
|
|
67208
|
+
appliesTo: appliesToOf(args5),
|
|
67209
|
+
minimumSubtotal: args5["min-subtotal"],
|
|
67210
|
+
minimumQuantity: numberOf3(args5["min-quantity"]),
|
|
67211
|
+
startsAt: args5.starts,
|
|
67212
|
+
endsAt: args5.ends,
|
|
67213
|
+
usageLimit: numberOf3(args5.limit),
|
|
67214
|
+
oncePerCustomer: args5["any-times"] === true ? false : void 0,
|
|
67215
|
+
combinesWith: combinesOf(args5.combines)
|
|
67216
|
+
});
|
|
67217
|
+
}
|
|
67218
|
+
var discountCreate = leaf(
|
|
67219
|
+
"shopify.change.discount.create",
|
|
67220
|
+
{
|
|
67221
|
+
name: "create",
|
|
67222
|
+
description: "Create a discount code for everyone who has it. Changes money: the user must say yes in the chat first \u2014 the command hands you the exact question. Example: baker shopify change discount create --code SPRING10 --percent 10 --ends 2026-10-12T23:59:00Z --limit 500. Applies to everything unless --products or --collections; starts when published unless --starts."
|
|
67223
|
+
},
|
|
67224
|
+
{
|
|
67225
|
+
code: { type: "string", description: "The code shoppers type, e.g. SPRING10", required: false },
|
|
67226
|
+
title: { type: "string", description: "What the store's staff see (default: the code)", required: false },
|
|
67227
|
+
percent: { type: "string", description: "Percentage off, 1-100", required: false },
|
|
67228
|
+
amount: { type: "string", description: "Amount off, as a decimal in the store's currency", required: false },
|
|
67229
|
+
products: { type: "string", description: "Only these products, comma separated", required: false },
|
|
67230
|
+
collections: { type: "string", description: "Only these collections, comma separated", required: false },
|
|
67231
|
+
"min-subtotal": { type: "string", description: "Minimum order amount", required: false },
|
|
67232
|
+
"min-quantity": { type: "string", description: "Minimum number of items", required: false },
|
|
67233
|
+
starts: { type: "string", description: "Start, ISO date-time (default: when published)", required: false },
|
|
67234
|
+
ends: { type: "string", description: "End, ISO date-time (default: no end)", required: false },
|
|
67235
|
+
limit: { type: "string", description: "Total number of uses", required: false },
|
|
67236
|
+
"any-times": { type: "boolean", description: "A customer may use it more than once", required: false },
|
|
67237
|
+
combines: {
|
|
67238
|
+
type: "string",
|
|
67239
|
+
description: "What it combines with, comma separated: product, order, shipping",
|
|
67240
|
+
required: false
|
|
67241
|
+
},
|
|
67242
|
+
...JSON_ARGS
|
|
67243
|
+
},
|
|
67244
|
+
async (args5) => await stageFor("shopify.discountCode.create", args5, () => discountPayload(args5))
|
|
67245
|
+
);
|
|
67246
|
+
var discountStop = leaf(
|
|
67247
|
+
"shopify.change.discount.stop",
|
|
67248
|
+
{
|
|
67249
|
+
name: "stop",
|
|
67250
|
+
description: "Stop a discount code (it ends when published). Changes money: needs the user's yes. Undo puts its own dates back. Example: baker shopify change discount stop SPRING10"
|
|
67251
|
+
},
|
|
67252
|
+
{ code: TARGET("The discount code") },
|
|
67253
|
+
async (args5) => await stage([{ kind: "shopify.discountCode.deactivate", target: target3(args5, "code") }])
|
|
67254
|
+
);
|
|
67255
|
+
var discountDates = leaf(
|
|
67256
|
+
"shopify.change.discount.dates",
|
|
67257
|
+
{
|
|
67258
|
+
name: "dates",
|
|
67259
|
+
description: "Change when a discount code runs. Changes money: needs the user's yes. Example: baker shopify change discount dates SPRING10 --starts 2026-10-01T00:00:00Z --ends never"
|
|
67260
|
+
},
|
|
67261
|
+
{
|
|
67262
|
+
code: TARGET("The discount code"),
|
|
67263
|
+
starts: { type: "string", description: "Start, ISO date-time", required: false },
|
|
67264
|
+
ends: { type: "string", description: 'End, ISO date-time, or "never"', required: false }
|
|
67265
|
+
},
|
|
67266
|
+
async (args5) => {
|
|
67267
|
+
if (typeof args5.starts !== "string" || typeof args5.ends !== "string") failValidation3("pass --starts and --ends");
|
|
67268
|
+
await stage([
|
|
67269
|
+
{
|
|
67270
|
+
kind: "shopify.discountCode.schedule",
|
|
67271
|
+
target: target3(args5, "code"),
|
|
67272
|
+
payload: { startsAt: args5.starts, endsAt: args5.ends === "never" ? null : args5.ends }
|
|
67273
|
+
}
|
|
67274
|
+
]);
|
|
67275
|
+
}
|
|
67276
|
+
);
|
|
67277
|
+
var redirectCreate = leaf(
|
|
67278
|
+
"shopify.change.redirect.create",
|
|
67279
|
+
{
|
|
67280
|
+
name: "create",
|
|
67281
|
+
description: "Redirect an old address on the store to a new one (store paths, or a full https link). Example: baker shopify change redirect create --from /collections/old-boards --to /collections/summer-boards"
|
|
67282
|
+
},
|
|
67283
|
+
{
|
|
67284
|
+
from: { type: "string", description: "The old path, starting with /", required: false },
|
|
67285
|
+
to: { type: "string", description: "Where it sends shoppers: a path or an https link", required: false },
|
|
67286
|
+
...JSON_ARGS
|
|
67287
|
+
},
|
|
67288
|
+
async (args5) => await stageFor("shopify.urlRedirect.create", args5, () => defined({ from: args5.from, to: args5.to }))
|
|
67289
|
+
);
|
|
67290
|
+
var redirectRemove = leaf(
|
|
67291
|
+
"shopify.change.redirect.remove",
|
|
67292
|
+
{
|
|
67293
|
+
name: "remove",
|
|
67294
|
+
description: "Remove a redirect, by the path it redirects. Example: baker shopify change redirect remove /old"
|
|
67295
|
+
},
|
|
67296
|
+
{ from: TARGET("The redirected path") },
|
|
67297
|
+
async (args5) => await stage([{ kind: "shopify.urlRedirect.delete", target: target3(args5, "path") }])
|
|
67298
|
+
);
|
|
67299
|
+
var campaignAdd = leaf(
|
|
67300
|
+
"shopify.change.campaign.add",
|
|
67301
|
+
{
|
|
67302
|
+
name: "add",
|
|
67303
|
+
description: "Show a Baker ad campaign in the store's Shopify Marketing, so Shopify's reports credit its sales; Baker then sends its daily figures. Title, status, budget and spend come from the ad platform. Example: baker shopify change campaign add --platform google-ads --account 3865083115 --campaign 2101 --utm-campaign spring --utm-source google --utm-medium cpc"
|
|
67304
|
+
},
|
|
67305
|
+
{
|
|
67306
|
+
platform: { type: "string", description: "google-ads | meta", required: false },
|
|
67307
|
+
account: { type: "string", description: "The ad account id", required: false },
|
|
67308
|
+
campaign: { type: "string", description: "The campaign id", required: false },
|
|
67309
|
+
"utm-campaign": { type: "string", description: "utm_campaign its links carry", required: false },
|
|
67310
|
+
"utm-source": { type: "string", description: "utm_source", required: false },
|
|
67311
|
+
"utm-medium": { type: "string", description: "utm_medium", required: false }
|
|
67312
|
+
},
|
|
67313
|
+
async (args5) => await stage([
|
|
67314
|
+
{
|
|
67315
|
+
kind: "shopify.marketingActivity.upsert",
|
|
67316
|
+
payload: {
|
|
67317
|
+
platform: args5.platform,
|
|
67318
|
+
accountId: args5.account,
|
|
67319
|
+
campaignId: args5.campaign,
|
|
67320
|
+
utm: { campaign: args5["utm-campaign"], source: args5["utm-source"], medium: args5["utm-medium"] }
|
|
67321
|
+
}
|
|
67322
|
+
}
|
|
67323
|
+
])
|
|
67324
|
+
);
|
|
67325
|
+
var campaignRemove = leaf(
|
|
67326
|
+
"shopify.change.campaign.remove",
|
|
67327
|
+
{
|
|
67328
|
+
name: "remove",
|
|
67329
|
+
description: "Take a Baker campaign out of Shopify Marketing. Example: baker shopify change campaign remove google-ads:3865083115:2101"
|
|
67330
|
+
},
|
|
67331
|
+
{ campaign: TARGET("<platform>:<account>:<campaign>") },
|
|
67332
|
+
async (args5) => await stage([{ kind: "shopify.marketingActivity.delete", target: target3(args5, "campaign") }])
|
|
67333
|
+
);
|
|
67334
|
+
var measurementReconnect = leaf(
|
|
67335
|
+
"shopify.change.measurement.reconnect",
|
|
67336
|
+
{
|
|
67337
|
+
name: "reconnect",
|
|
67338
|
+
description: "Reconnect Baker's measurement on the store (the fix `baker shopify tracking audit` names when it is gone). Applies when published; Baker also repairs it on its own once a day."
|
|
67339
|
+
},
|
|
67340
|
+
{},
|
|
67341
|
+
async () => await stage([{ kind: "shopify.webPixel.update" }])
|
|
67342
|
+
);
|
|
67343
|
+
var group = (name, description, subCommands) => defineCommand211({ meta: { name, description }, subCommands });
|
|
67344
|
+
var changeCommand = defineCommand211({
|
|
67345
|
+
meta: {
|
|
67346
|
+
name: "change",
|
|
67347
|
+
description: `Stage a change to the connected store. Nothing changes until the user publishes the chat; every
|
|
67348
|
+
change can be put back with \`baker shopify undo\`. Prices and discounts need the user's yes first.
|
|
67349
|
+
|
|
67350
|
+
baker shopify change product update <product> --title \u2026 --seo-title \u2026 --add-tags a,b
|
|
67351
|
+
baker shopify change variant update <variantId> --sku \u2026 --barcode \u2026 --price \u2026
|
|
67352
|
+
baker shopify change field set product:<product> --namespace custom --key \u2026 --type \u2026 --value \u2026
|
|
67353
|
+
baker shopify change collection create --title \u2026 --products a,b
|
|
67354
|
+
baker shopify change discount create --code SPRING10 --percent 10 --ends <iso>
|
|
67355
|
+
baker shopify change redirect create --from /old --to /new
|
|
67356
|
+
baker shopify change campaign add --platform google-ads --account \u2026 --campaign \u2026
|
|
67357
|
+
baker shopify change measurement reconnect`
|
|
67358
|
+
},
|
|
67359
|
+
subCommands: {
|
|
67360
|
+
product: group("product", "Change a product's title, description, SEO, tags or type", { update: productUpdate }),
|
|
67361
|
+
variant: group("variant", "Change an option's SKU, barcode, weight or price", { update: variantUpdate }),
|
|
67362
|
+
field: group("field", "Set or remove a custom field", { set: fieldSet, remove: fieldRemove }),
|
|
67363
|
+
collection: group("collection", "Create, change, show, hide, fill or delete a collection", {
|
|
67364
|
+
create: collectionCreate,
|
|
67365
|
+
update: collectionUpdate,
|
|
67366
|
+
show: collectionVerb(
|
|
67367
|
+
"show",
|
|
67368
|
+
"shopify.collection.publish",
|
|
67369
|
+
"Show a collection on the online store. Example: baker shopify change collection show summer-boards"
|
|
67370
|
+
),
|
|
67371
|
+
hide: collectionVerb(
|
|
67372
|
+
"hide",
|
|
67373
|
+
"shopify.collection.unpublish",
|
|
67374
|
+
"Hide a collection from the online store. Example: baker shopify change collection hide summer-boards"
|
|
67375
|
+
),
|
|
67376
|
+
delete: collectionVerb(
|
|
67377
|
+
"delete",
|
|
67378
|
+
"shopify.collection.delete",
|
|
67379
|
+
"Delete a collection \u2014 only one undo could rebuild exactly (hand-picked products, no image, no custom fields, no discount or menu pointing at it); refused otherwise with the reason. Stage a redirect for its address. Example: baker shopify change collection delete old-boards"
|
|
67380
|
+
),
|
|
67381
|
+
add: membership(
|
|
67382
|
+
"add",
|
|
67383
|
+
"shopify.collection.addProducts",
|
|
67384
|
+
"Add products to a collection. Example: baker shopify change collection add summer-boards snowboard-a snowboard-b"
|
|
67385
|
+
),
|
|
67386
|
+
remove: membership(
|
|
67387
|
+
"remove",
|
|
67388
|
+
"shopify.collection.removeProducts",
|
|
67389
|
+
"Remove products from a collection. Example: baker shopify change collection remove summer-boards snowboard-a"
|
|
67390
|
+
)
|
|
67391
|
+
}),
|
|
67392
|
+
discount: group("discount", "Create, stop or reschedule a discount code (needs the user's yes)", {
|
|
67393
|
+
create: discountCreate,
|
|
67394
|
+
stop: discountStop,
|
|
67395
|
+
dates: discountDates
|
|
67396
|
+
}),
|
|
67397
|
+
redirect: group("redirect", "Create or remove a redirect", { create: redirectCreate, remove: redirectRemove }),
|
|
67398
|
+
campaign: group("campaign", "Show or remove a Baker campaign in Shopify Marketing", {
|
|
67399
|
+
add: campaignAdd,
|
|
67400
|
+
remove: campaignRemove
|
|
67401
|
+
}),
|
|
67402
|
+
measurement: group("measurement", "Reconnect Baker's measurement on the store", {
|
|
67403
|
+
reconnect: measurementReconnect
|
|
67404
|
+
})
|
|
67405
|
+
}
|
|
67406
|
+
});
|
|
67407
|
+
|
|
67408
|
+
// src/commands/shopify/changes.ts
|
|
67409
|
+
var changesCommand2 = leaf(
|
|
67410
|
+
"shopify.changes",
|
|
67411
|
+
{
|
|
67412
|
+
name: "changes",
|
|
67413
|
+
description: "The changes Baker made to the store, newest first, each with its changeId and whether it can be undone. Example: baker shopify changes --limit 20 (or --chat <id> for one chat's)."
|
|
67414
|
+
},
|
|
67415
|
+
{
|
|
67416
|
+
limit: { type: "string", description: "How many, 1-100 (default 20)", required: false },
|
|
67417
|
+
chat: { type: "string", description: "Only one chat's changes", required: false }
|
|
67418
|
+
},
|
|
67419
|
+
async (args5) => {
|
|
67420
|
+
try {
|
|
67421
|
+
const data = await apiGet(
|
|
67422
|
+
"/api/shopify/changes",
|
|
67423
|
+
params({ limit: args5.limit, chatId: args5.chat })
|
|
67424
|
+
);
|
|
67425
|
+
writeJson({ ok: true, hints: changesHints(data), data });
|
|
67426
|
+
} catch (err) {
|
|
67427
|
+
failChange(err);
|
|
67428
|
+
}
|
|
67429
|
+
}
|
|
67430
|
+
);
|
|
67431
|
+
var undoCommand = leaf(
|
|
67432
|
+
"shopify.undo",
|
|
67433
|
+
{
|
|
67434
|
+
name: "undo",
|
|
67435
|
+
description: "Stage the change that puts an applied store change back, read from the store as it was before it \u2014 applied when the user publishes, like any change. Prices and discounts ask the user again. Refused when the store changed since. Example: baker shopify undo <changeId> [<changeId>\u2026]"
|
|
67436
|
+
},
|
|
67437
|
+
{ changeIds: { type: "positional", description: "changeIds from `baker shopify changes`", required: false } },
|
|
67438
|
+
async (args5) => {
|
|
67439
|
+
const changeIds = Array.isArray(args5._) ? args5._.filter((value) => typeof value === "string") : [];
|
|
67440
|
+
if (changeIds.length === 0) failValidation3("pass the changeIds to undo (see `baker shopify changes`)");
|
|
67441
|
+
try {
|
|
67442
|
+
const data = await apiPost("/api/shopify/undo", {
|
|
67443
|
+
chatId: requireChatId(),
|
|
67444
|
+
changeIds
|
|
67445
|
+
});
|
|
67446
|
+
emitStage(data);
|
|
67447
|
+
} catch (err) {
|
|
67448
|
+
failChange(err);
|
|
67449
|
+
}
|
|
67450
|
+
}
|
|
67451
|
+
);
|
|
67452
|
+
|
|
67453
|
+
// src/commands/shopify/draft.ts
|
|
67454
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
67455
|
+
function refOf(args5) {
|
|
67456
|
+
const [ref] = Array.isArray(args5._) ? args5._ : [];
|
|
67457
|
+
if (typeof ref !== "string" || ref === "")
|
|
67458
|
+
failValidation3("pass the staged change's ref (see `baker shopify draft list`)");
|
|
67459
|
+
return ref;
|
|
67460
|
+
}
|
|
67461
|
+
function listHints(data) {
|
|
67462
|
+
if (data.status === "none" || data.count === 0) return ["No store changes are staged on this chat."];
|
|
67463
|
+
if (data.status === "active") {
|
|
67464
|
+
return [
|
|
67465
|
+
"Staged only: these apply when the user publishes the chat. Correct one with `baker shopify draft amend <ref>`, drop one with `remove`."
|
|
67466
|
+
];
|
|
67467
|
+
}
|
|
67468
|
+
const failed = data.ops.filter((op) => op.result?.status === "failed" || op.result?.status === "skipped");
|
|
67469
|
+
return failed.length > 0 ? [`${failed.length} of ${data.count} changes did not go through \u2014 say which and why; never report them as made.`] : [];
|
|
67470
|
+
}
|
|
67471
|
+
var list2 = leaf(
|
|
67472
|
+
"shopify.draft.list",
|
|
67473
|
+
{
|
|
67474
|
+
name: "list",
|
|
67475
|
+
description: "Start here to review the store changes staged on this chat (or another chat's with --chat): what each is, whether it changes money, and after publish what happened to it."
|
|
67476
|
+
},
|
|
67477
|
+
{ chat: CHAT_READ_ARG },
|
|
67478
|
+
async (args5) => {
|
|
67479
|
+
try {
|
|
67480
|
+
const data = await apiPost("/api/shopify/draft/list", {
|
|
67481
|
+
chatId: resolveChatId(args5.chat)
|
|
67482
|
+
});
|
|
67483
|
+
writeJson({ ok: true, hints: listHints(data), data });
|
|
67484
|
+
} catch (err) {
|
|
67485
|
+
failChange(err);
|
|
67486
|
+
}
|
|
67487
|
+
}
|
|
67488
|
+
);
|
|
67489
|
+
var show = leaf(
|
|
67490
|
+
"shopify.draft.show",
|
|
67491
|
+
{
|
|
67492
|
+
name: "show",
|
|
67493
|
+
description: "One staged store change in full: what it sends and the store as it was read when it was staged (the before)."
|
|
67494
|
+
},
|
|
67495
|
+
{ ref: { type: "positional", description: "The staged change's ref", required: false }, chat: CHAT_READ_ARG },
|
|
67496
|
+
async (args5) => {
|
|
67497
|
+
try {
|
|
67498
|
+
const data = await apiPost("/api/shopify/draft/show", { chatId: resolveChatId(args5.chat), ref: refOf(args5) });
|
|
67499
|
+
writeJson({ ok: true, data });
|
|
67500
|
+
} catch (err) {
|
|
67501
|
+
failChange(err);
|
|
67502
|
+
}
|
|
67503
|
+
}
|
|
67504
|
+
);
|
|
67505
|
+
var amend = leaf(
|
|
67506
|
+
"shopify.draft.amend",
|
|
67507
|
+
{
|
|
67508
|
+
name: "amend",
|
|
67509
|
+
description: `Correct a staged change in place: a JSON patch merged into its payload (objects merge, null removes a key) and every check run again \u2014 a changed price asks the user again. Example: baker shopify draft amend product:123 --patch '{"title":"Better"}'. Keys are the payload's, not the flags': productType (not type), seo {title, description}, addTags, compareAtPrice; a key it doesn't take is refused with the ones it does.`
|
|
67510
|
+
},
|
|
67511
|
+
{
|
|
67512
|
+
ref: { type: "positional", description: "The staged change's ref", required: false },
|
|
67513
|
+
patch: { type: "string", description: "Inline JSON patch", required: false },
|
|
67514
|
+
file: { type: "string", description: "A JSON file with the patch", required: false }
|
|
67515
|
+
},
|
|
67516
|
+
async (args5) => {
|
|
67517
|
+
try {
|
|
67518
|
+
const data = await apiPost("/api/shopify/draft/amend", {
|
|
67519
|
+
chatId: requireChatId(),
|
|
67520
|
+
ref: refOf(args5),
|
|
67521
|
+
patch: loadJsonArg(args5, "patch")
|
|
67522
|
+
});
|
|
67523
|
+
emitStage(data);
|
|
67524
|
+
} catch (err) {
|
|
67525
|
+
failChange(err);
|
|
67526
|
+
}
|
|
67527
|
+
}
|
|
67528
|
+
);
|
|
67529
|
+
var remove = leaf(
|
|
67530
|
+
"shopify.draft.remove",
|
|
67531
|
+
{
|
|
67532
|
+
name: "remove",
|
|
67533
|
+
description: "Drop one staged store change, and any change that needs it (a new collection's show)."
|
|
67534
|
+
},
|
|
67535
|
+
{ ref: { type: "positional", description: "The staged change's ref", required: false } },
|
|
67536
|
+
async (args5) => {
|
|
67537
|
+
try {
|
|
67538
|
+
writeJson({
|
|
67539
|
+
ok: true,
|
|
67540
|
+
data: await apiPost("/api/shopify/draft/remove", { chatId: requireChatId(), ref: refOf(args5) })
|
|
67541
|
+
});
|
|
67542
|
+
} catch (err) {
|
|
67543
|
+
failChange(err);
|
|
67544
|
+
}
|
|
67545
|
+
}
|
|
67546
|
+
);
|
|
67547
|
+
var clear = leaf(
|
|
67548
|
+
"shopify.draft.clear",
|
|
67549
|
+
{ name: "clear", description: "Drop every store change staged on this chat." },
|
|
67550
|
+
{},
|
|
67551
|
+
async () => {
|
|
67552
|
+
try {
|
|
67553
|
+
writeJson({ ok: true, data: await apiPost("/api/shopify/draft/clear", { chatId: requireChatId() }) });
|
|
67554
|
+
} catch (err) {
|
|
67555
|
+
failChange(err);
|
|
67556
|
+
}
|
|
67557
|
+
}
|
|
67558
|
+
);
|
|
67559
|
+
var draftCommand5 = defineCommand212({
|
|
67560
|
+
meta: { name: "draft", description: "List, show, amend, remove or clear the store changes staged on this chat" },
|
|
67561
|
+
subCommands: { list: list2, show, amend, remove, clear }
|
|
67562
|
+
});
|
|
67563
|
+
|
|
67564
|
+
// src/commands/shopify/promotions.ts
|
|
67565
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
67566
|
+
|
|
66431
67567
|
// src/commands/shopify/landingLinks.ts
|
|
66432
67568
|
import { readdir as readdir16, readFile as readFile33, stat as stat11 } from "fs/promises";
|
|
66433
67569
|
import path47 from "path";
|
|
@@ -66460,9 +67596,9 @@ function landingLinksOf(pages, keys) {
|
|
|
66460
67596
|
const order = ["buy_link", "product_page", "variant_id"];
|
|
66461
67597
|
return [...bySlug].map(([slug, evidence]) => ({ slug, evidence: order.filter((entry) => evidence.has(entry)) }));
|
|
66462
67598
|
}
|
|
66463
|
-
async function isDir4(
|
|
67599
|
+
async function isDir4(target4) {
|
|
66464
67600
|
try {
|
|
66465
|
-
return (await stat11(
|
|
67601
|
+
return (await stat11(target4)).isDirectory();
|
|
66466
67602
|
} catch {
|
|
66467
67603
|
return false;
|
|
66468
67604
|
}
|
|
@@ -66500,8 +67636,8 @@ function plural(count2, one, many = `${one}s`) {
|
|
|
66500
67636
|
}
|
|
66501
67637
|
function pauseCommand2(ad) {
|
|
66502
67638
|
if (ad.platform === "meta") return `\`baker ads meta ads pause ${ad.id ?? "<id>"}\``;
|
|
66503
|
-
const
|
|
66504
|
-
return ad.level === "asset_group" ? `\`baker ads google asset-groups update ${
|
|
67639
|
+
const target4 = `${ad.resource ?? "<resource>"} --customer-id ${ad.account_id ?? "<account_id>"}`;
|
|
67640
|
+
return ad.level === "asset_group" ? `\`baker ads google asset-groups update ${target4} --status PAUSED\`` : `\`baker ads google ads pause ${target4}\``;
|
|
66505
67641
|
}
|
|
66506
67642
|
function pauseHint(answer) {
|
|
66507
67643
|
if (answer.product.stock === "in_stock" || answer.ads.length === 0) return null;
|
|
@@ -66510,8 +67646,7 @@ function pauseHint(answer) {
|
|
|
66510
67646
|
return `Every ad that sends people to \u201C${answer.product.title}\u201D is already paused: stage nothing for it. Tell the user this run paused nothing, and promise nothing about these ads coming back when it is back in stock.`;
|
|
66511
67647
|
}
|
|
66512
67648
|
const one = active.length === 1;
|
|
66513
|
-
|
|
66514
|
-
return `${plural(active.length, "active ad")} still ${one ? "sends" : "send"} people to \u201C${answer.product.title}\u201D, which is out of stock. Stage pausing ${one ? "it" : "them"}: ${active.map(pauseCommand2).join("; ")}. Each pause waits for the user to review and publish, and nothing turns it back on by itself.${remembered}`;
|
|
67649
|
+
return `${plural(active.length, "active ad")} still ${one ? "sends" : "send"} people to \u201C${answer.product.title}\u201D, which is out of stock. Stage pausing ${one ? "it" : "them"}: ${active.map(pauseCommand2).join("; ")}. Each pause waits for the user to review and publish, and nothing turns it back on by itself.`;
|
|
66515
67650
|
}
|
|
66516
67651
|
function promotionHints(answer, scan) {
|
|
66517
67652
|
const hints2 = [];
|
|
@@ -66545,13 +67680,23 @@ function promotionHints(answer, scan) {
|
|
|
66545
67680
|
}
|
|
66546
67681
|
if (!answer.remembered && answer.ads.length > 0) {
|
|
66547
67682
|
hints2.push(
|
|
66548
|
-
"This read was
|
|
67683
|
+
"This read was made outside a Session (no chat): a pause staged from it will never be offered back for restarting when the product returns."
|
|
66549
67684
|
);
|
|
66550
67685
|
}
|
|
66551
67686
|
return hints2;
|
|
66552
67687
|
}
|
|
66553
|
-
|
|
66554
|
-
|
|
67688
|
+
|
|
67689
|
+
// src/commands/shopify/stockHoldReport.ts
|
|
67690
|
+
var PLATFORM2 = { "google-ads": "Google Ads", meta: "Meta" };
|
|
67691
|
+
var LEVEL = {
|
|
67692
|
+
campaign: "campaign",
|
|
67693
|
+
ad_group: "ad group",
|
|
67694
|
+
ad: "ad",
|
|
67695
|
+
asset_group: "asset group",
|
|
67696
|
+
adset: "ad set"
|
|
67697
|
+
};
|
|
67698
|
+
function adName(ad) {
|
|
67699
|
+
return `${PLATFORM2[ad.platform]} ${LEVEL[ad.level]} ${ad.name ? `\u201C${ad.name}\u201D` : ad.entity_id}`;
|
|
66555
67700
|
}
|
|
66556
67701
|
var GOOGLE_GROUP = {
|
|
66557
67702
|
campaign: "campaigns",
|
|
@@ -66560,10 +67705,6 @@ var GOOGLE_GROUP = {
|
|
|
66560
67705
|
asset_group: "asset-groups",
|
|
66561
67706
|
adset: "ads"
|
|
66562
67707
|
};
|
|
66563
|
-
function googleResume(hold) {
|
|
66564
|
-
const target2 = `${hold.entity_id} --customer-id ${hold.account_id}`;
|
|
66565
|
-
return hold.level === "asset_group" ? `baker ads google asset-groups update ${target2} --status ENABLED` : `baker ads google ${GOOGLE_GROUP[hold.level]} resume ${target2}`;
|
|
66566
|
-
}
|
|
66567
67708
|
var META_GROUP = {
|
|
66568
67709
|
campaign: "campaigns",
|
|
66569
67710
|
ad_group: "adsets",
|
|
@@ -66572,65 +67713,86 @@ var META_GROUP = {
|
|
|
66572
67713
|
adset: "adsets"
|
|
66573
67714
|
};
|
|
66574
67715
|
function resumeCommand2(hold) {
|
|
66575
|
-
|
|
67716
|
+
if (hold.platform === "meta") return `baker ads meta ${META_GROUP[hold.level]} resume ${hold.entity_id}`;
|
|
67717
|
+
const target4 = `${hold.entity_id} --customer-id ${hold.account_id}`;
|
|
67718
|
+
return hold.level === "asset_group" ? `baker ads google asset-groups update ${target4} --status ENABLED` : `baker ads google ${GOOGLE_GROUP[hold.level]} resume ${target4}`;
|
|
66576
67719
|
}
|
|
66577
|
-
|
|
66578
|
-
|
|
66579
|
-
changed_by_baker: "turned back on by other work published in Baker",
|
|
66580
|
-
already_active: "found running again, turned back on by someone",
|
|
66581
|
-
removed: "removed",
|
|
66582
|
-
product_removed: "let go when the product left the store"
|
|
66583
|
-
};
|
|
66584
|
-
function nothingHeldHint(answer, asked) {
|
|
66585
|
-
if (!asked.product) return "No ad is still paused because a product ran out: there is nothing to resume.";
|
|
66586
|
-
if (answer.pending_sessions.length > 0) {
|
|
66587
|
-
return "The latest pause for this product is still waiting for review and was never published, so nothing is paused and there is nothing to resume.";
|
|
66588
|
-
}
|
|
66589
|
-
const closed = answer.recently_closed;
|
|
66590
|
-
if (closed.length > 0) {
|
|
66591
|
-
const each = closed.map((hold) => `Baker paused ${holdName(hold)} for it, and it was later ${CLOSED_HOW[hold.resolved_reason]}`).join("; ");
|
|
66592
|
-
return `Nothing is still paused because this product ran out, so there is nothing to resume: ${each}. Tell the user that, naming only ${closed.length === 1 ? "this ad" : "these ads"} \u2014 never that nothing was paused, and never whether an ad is running now.`;
|
|
66593
|
-
}
|
|
66594
|
-
if (answer.holds.length > 0) return "None of these is still paused because its product ran out: nothing to resume.";
|
|
66595
|
-
return "Baker has no pause on record for this product running out: there is nothing to resume.";
|
|
67720
|
+
function quoted(title, fallback) {
|
|
67721
|
+
return title ? `\u201C${title}\u201D` : fallback;
|
|
66596
67722
|
}
|
|
66597
|
-
function
|
|
66598
|
-
const name =
|
|
67723
|
+
function heldLine(hold) {
|
|
67724
|
+
const name = adName(hold);
|
|
67725
|
+
const product = quoted(hold.product.title, "the product");
|
|
66599
67726
|
switch (hold.verdict) {
|
|
67727
|
+
case "resumable":
|
|
67728
|
+
return `Ready to turn back on when you publish: ${name} \u2014 Baker paused it because ${product} ran out.`;
|
|
66600
67729
|
case "still_out_of_stock":
|
|
66601
|
-
return
|
|
67730
|
+
return `Stays paused: ${name} \u2014 ${product} still cannot be bought.`;
|
|
66602
67731
|
case "changed_since":
|
|
66603
|
-
return
|
|
67732
|
+
return `Left as it is: ${name} \u2014 someone changed it after Baker paused it when ${product} ran out, so check it yourself.`;
|
|
66604
67733
|
case "still_promotes_out_of_stock":
|
|
66605
|
-
return
|
|
67734
|
+
return `Stays paused: ${name} \u2014 it also sends people to ${quoted(hold.verdict_detail, "another product")}, which is still out of stock.`;
|
|
66606
67735
|
case "cannot_confirm":
|
|
66607
|
-
return
|
|
67736
|
+
return `Left as it is: ${name} \u2014 Baker cannot tell whether someone changed it after pausing it when ${product} ran out, so check it before turning it back on.`;
|
|
66608
67737
|
case "already_active":
|
|
66609
|
-
return
|
|
67738
|
+
return `Nothing to do: ${name} is already running again.`;
|
|
66610
67739
|
default:
|
|
66611
67740
|
return null;
|
|
66612
67741
|
}
|
|
66613
67742
|
}
|
|
66614
|
-
|
|
66615
|
-
|
|
66616
|
-
|
|
66617
|
-
|
|
66618
|
-
|
|
66619
|
-
|
|
66620
|
-
|
|
66621
|
-
|
|
66622
|
-
|
|
67743
|
+
var CLOSED_HOW = {
|
|
67744
|
+
resumed_by_back_in_stock_run: "turned back on by an earlier back-in-stock run",
|
|
67745
|
+
changed_by_baker: "turned back on by other work published in Baker",
|
|
67746
|
+
already_active: "found running again, turned back on by someone",
|
|
67747
|
+
removed: "removed",
|
|
67748
|
+
product_removed: "let go when the product left the store"
|
|
67749
|
+
};
|
|
67750
|
+
function plural2(count2, one) {
|
|
67751
|
+
return `${count2} ${count2 === 1 ? one : `${one}s`}`;
|
|
67752
|
+
}
|
|
67753
|
+
function nothingHeldLines(answer, asked, product) {
|
|
67754
|
+
if (!asked.product) {
|
|
67755
|
+
return answer.holds.length > 0 ? ["None of these is still paused because its product ran out, so there is nothing to turn back on."] : ["Baker has no ad paused because a product ran out, so there is nothing to turn back on."];
|
|
66623
67756
|
}
|
|
66624
|
-
|
|
66625
|
-
|
|
66626
|
-
|
|
67757
|
+
if (answer.pending_sessions.length > 0) {
|
|
67758
|
+
return [
|
|
67759
|
+
`Baker's pause for ${product} is still waiting for your review and was never published, so there is nothing to turn back on.`
|
|
67760
|
+
];
|
|
66627
67761
|
}
|
|
66628
|
-
|
|
66629
|
-
|
|
66630
|
-
`
|
|
67762
|
+
if (answer.recently_closed.length > 0) {
|
|
67763
|
+
return answer.recently_closed.map(
|
|
67764
|
+
(hold) => `Already handled: Baker paused ${adName(hold)} when ${product} ran out, and it was later ${CLOSED_HOW[hold.resolved_reason]}.`
|
|
66631
67765
|
);
|
|
66632
67766
|
}
|
|
66633
|
-
return
|
|
67767
|
+
return [`Baker has nothing paused because ${product} ran out, so there is nothing to turn back on.`];
|
|
67768
|
+
}
|
|
67769
|
+
function stockHoldReport(answer, asked) {
|
|
67770
|
+
const product = quoted(answer.product?.title, "the product that came back");
|
|
67771
|
+
const held = answer.holds.filter((hold) => hold.state === "held");
|
|
67772
|
+
const tell_user = [
|
|
67773
|
+
...held.length === 0 ? nothingHeldLines(answer, asked, product) : [],
|
|
67774
|
+
...held.flatMap((hold) => heldLine(hold) ?? []),
|
|
67775
|
+
...answer.not_paused.map((ad) => `Left as it is: ${adName(ad)} \u2014 Baker did not pause it when ${product} ran out.`),
|
|
67776
|
+
...answer.pending_sessions.map(
|
|
67777
|
+
(pending) => `Discard the work waiting for your review, \u201C${pending.title}\u201D: it would pause ${plural2(pending.staged_pauses, "ad")} for ${product}, which can be bought again.`
|
|
67778
|
+
)
|
|
67779
|
+
];
|
|
67780
|
+
const resume = held.filter((hold) => hold.verdict === "resumable").map((hold) => ({ ad: adName(hold), command: resumeCommand2(hold) }));
|
|
67781
|
+
const pages = answer.pages_changed.map((run) => ({
|
|
67782
|
+
pages: run.pages.map((slug) => `/${slug}`),
|
|
67783
|
+
read: `baker chats diff ${run.chat_id} --surface landings --full`
|
|
67784
|
+
}));
|
|
67785
|
+
const hints2 = [
|
|
67786
|
+
resume.length > 0 ? "Stage each `resume` command, and nothing else." : `Stage nothing${asked.product ? ` for ${product}` : ""}.`,
|
|
67787
|
+
"Tell the user the `tell_user` lines as they are written, and nothing about any other ad: an ad this read does not name is not this run's to explain.",
|
|
67788
|
+
...pages.map(
|
|
67789
|
+
(run) => `The out-of-stock run also changed ${run.pages.join(", ")}: read those changes with its \`read\` command, and put back only what it changed for ${product}.`
|
|
67790
|
+
)
|
|
67791
|
+
];
|
|
67792
|
+
const compact3 = { tell_user, resume, ...pages.length > 0 ? { pages } : {} };
|
|
67793
|
+
if (!asked.full) return { data: compact3, hints: hints2 };
|
|
67794
|
+
const { store: _store, ...everything } = answer;
|
|
67795
|
+
return { data: { ...compact3, ...everything }, hints: hints2 };
|
|
66634
67796
|
}
|
|
66635
67797
|
|
|
66636
67798
|
// src/commands/shopify/promotions.ts
|
|
@@ -66647,14 +67809,19 @@ registerSchema({
|
|
|
66647
67809
|
});
|
|
66648
67810
|
registerSchema({
|
|
66649
67811
|
command: "shopify.stock-holds",
|
|
66650
|
-
description: "Start here when a product is back in stock:
|
|
67812
|
+
description: "Start here when a product is back in stock: what Baker paused because it ran out, answered for the marketer. `resume` holds the one command to stage per ad Baker may turn back on now \u2014 stage those and nothing else. `tell_user` holds one sentence per ad (and per piece of out-of-stock work still waiting for review), written for the marketer: tell them those, as written. `pages` names landings the out-of-stock run changed and the read that shows those page changes. Use `--product` for the product that came back: the answer then speaks only of its ads. `--full` adds the codes behind each sentence (verdicts, ids) for debugging, never for the user.",
|
|
66651
67813
|
args: {
|
|
66652
67814
|
product: { type: "string", description: "Only one product's holds: its id, handle or link", required: false },
|
|
66653
67815
|
all: { type: "boolean", description: "Resolved holds too (resumed or released)", required: false, default: false },
|
|
66654
67816
|
full: fullArg
|
|
66655
67817
|
}
|
|
66656
67818
|
});
|
|
66657
|
-
|
|
67819
|
+
function promotionsShown(answer, full) {
|
|
67820
|
+
if (full) return answer;
|
|
67821
|
+
const { remembered: _remembered, ...shown } = answer;
|
|
67822
|
+
return shown;
|
|
67823
|
+
}
|
|
67824
|
+
var promotionsCommand = defineCommand213({
|
|
66658
67825
|
meta: {
|
|
66659
67826
|
name: "promotions",
|
|
66660
67827
|
description: "What advertises one product: ads that lead to it, landings that link to it, Shopping that shows it. Example: baker shopify promotions 10310413942969"
|
|
@@ -66670,8 +67837,8 @@ var promotionsCommand = defineCommand210({
|
|
|
66670
67837
|
},
|
|
66671
67838
|
run: async ({ args: args5 }) => {
|
|
66672
67839
|
try {
|
|
66673
|
-
const
|
|
66674
|
-
if (
|
|
67840
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
67841
|
+
if (positionals2.length > 1) {
|
|
66675
67842
|
throw new ApiError("VALIDATION_ERROR", "product: Pass one product id, handle or product link.");
|
|
66676
67843
|
}
|
|
66677
67844
|
const { product, store } = await apiGet(
|
|
@@ -66690,7 +67857,7 @@ var promotionsCommand = defineCommand210({
|
|
|
66690
67857
|
scanned: scan !== null,
|
|
66691
67858
|
...args5.full ? { full: true } : {}
|
|
66692
67859
|
});
|
|
66693
|
-
emit2(answer, { store }, [
|
|
67860
|
+
emit2(promotionsShown(answer, args5.full === true), { store }, [
|
|
66694
67861
|
...storeStateHints(store),
|
|
66695
67862
|
...promotionHints(answer, { scanned: scan !== null, skippedPages: scan?.skipped ?? 0 })
|
|
66696
67863
|
]);
|
|
@@ -66699,7 +67866,7 @@ var promotionsCommand = defineCommand210({
|
|
|
66699
67866
|
}
|
|
66700
67867
|
}
|
|
66701
67868
|
});
|
|
66702
|
-
var stockHoldsCommand =
|
|
67869
|
+
var stockHoldsCommand = defineCommand213({
|
|
66703
67870
|
meta: {
|
|
66704
67871
|
name: "stock-holds",
|
|
66705
67872
|
description: "The ads Baker paused because a product ran out, and whether each may be resumed now. Example: baker shopify stock-holds --product 10310413942969"
|
|
@@ -66715,10 +67882,10 @@ var stockHoldsCommand = defineCommand210({
|
|
|
66715
67882
|
"/api/shopify/stock-holds",
|
|
66716
67883
|
params({ product: args5.product, all: args5.all, full: args5.full })
|
|
66717
67884
|
);
|
|
66718
|
-
const {
|
|
66719
|
-
emit2(data, { store, count: answer.holds.length }, [
|
|
66720
|
-
...storeStateHints(store),
|
|
66721
|
-
...
|
|
67885
|
+
const report = stockHoldReport(answer, { product: args5.product !== void 0, full: args5.full === true });
|
|
67886
|
+
emit2(report.data, { store: answer.store, count: answer.holds.length }, [
|
|
67887
|
+
...storeStateHints(answer.store),
|
|
67888
|
+
...report.hints
|
|
66722
67889
|
]);
|
|
66723
67890
|
} catch (err) {
|
|
66724
67891
|
fail9(err);
|
|
@@ -66726,10 +67893,33 @@ var stockHoldsCommand = defineCommand210({
|
|
|
66726
67893
|
}
|
|
66727
67894
|
});
|
|
66728
67895
|
|
|
67896
|
+
// src/commands/shopify/tracking.ts
|
|
67897
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
67898
|
+
var audit = leaf(
|
|
67899
|
+
"shopify.tracking.audit",
|
|
67900
|
+
{
|
|
67901
|
+
name: "audit",
|
|
67902
|
+
description: "Start here for 'is our store's tracking set up right?': Baker's measurement on the store, Baker switched on in the theme, whether orders carry Baker's visitor, who reports sales to Meta and Google, shoppers' consent, and whether the store sells through its own website. Each check is ok, problem (with its fix: a change to stage, a task for the merchant, or a decision) or unknown (with why). Reads only \u2014 it changes nothing."
|
|
67903
|
+
},
|
|
67904
|
+
{ full: { type: "boolean", description: "Add the facts behind each check", required: false } },
|
|
67905
|
+
async (args5) => {
|
|
67906
|
+
try {
|
|
67907
|
+
const data = await apiPost("/api/shopify/tracking/audit", { full: args5.full === true });
|
|
67908
|
+
writeJson({ ok: true, hints: auditHints(data), data });
|
|
67909
|
+
} catch (err) {
|
|
67910
|
+
fail9(err);
|
|
67911
|
+
}
|
|
67912
|
+
}
|
|
67913
|
+
);
|
|
67914
|
+
var trackingCommand2 = defineCommand214({
|
|
67915
|
+
meta: { name: "tracking", description: "Check how the store is measured: baker shopify tracking audit" },
|
|
67916
|
+
subCommands: { audit }
|
|
67917
|
+
});
|
|
67918
|
+
|
|
66729
67919
|
// src/commands/shopify/index.ts
|
|
66730
67920
|
registerSchema({
|
|
66731
67921
|
command: "shopify.store",
|
|
66732
|
-
description: 'Start here for the connected Shopify store: its name, currency, home country, how many products and collections it has, how many products are out of stock or partly out, the prices by country it sells at (only when it has more than one), where its buy links send a shopper (`buyDestination`: checkout, store_cart or product_page), its languages and policies, whether it asks for a password, and the link to the Products page in Baker. `capped: true` means a count stopped at its ceiling (100 out of stock or partly out, 500 collections): say "100 or more", never the number as exact. `meta.store` says whether Baker\'s copy is complete and whether Baker can still reach the store.',
|
|
67922
|
+
description: 'Start here for the connected Shopify store: its name, currency, home country, how many products and collections it has, how many products are out of stock or partly out, the prices by country it sells at (only when it has more than one), where its buy links send a shopper (`buyDestination`: checkout, store_cart or product_page), its languages and policies, whether it asks for a password, and the link to the Products page in Baker. `capped: true` means a count stopped at its ceiling (100 out of stock or partly out, 500 collections): say "100 or more", never the number as exact. `meta.store` says whether Baker\'s copy is complete and whether Baker can still reach the store. `canChange` says which kinds of store change the store allows Baker to stage (products, publishing, discounts, redirects, marketing); a `false` one is allowed by the user in Shopify (`request_connection`).',
|
|
66733
67923
|
args: {
|
|
66734
67924
|
full: {
|
|
66735
67925
|
...fullArg,
|
|
@@ -66854,7 +68044,7 @@ registerSchema({
|
|
|
66854
68044
|
}
|
|
66855
68045
|
}
|
|
66856
68046
|
});
|
|
66857
|
-
var salesCommand =
|
|
68047
|
+
var salesCommand = defineCommand215({
|
|
66858
68048
|
meta: {
|
|
66859
68049
|
name: "sales",
|
|
66860
68050
|
description: "What the store sold: orders, sales, refunds and net, by day, product, campaign or landing \u2014 or when buyers order (weekday, hour, month). Example: baker shopify sales --days 7 --by campaign"
|
|
@@ -66892,7 +68082,7 @@ var salesCommand = defineCommand211({
|
|
|
66892
68082
|
}
|
|
66893
68083
|
}
|
|
66894
68084
|
});
|
|
66895
|
-
var storeCommand =
|
|
68085
|
+
var storeCommand = defineCommand215({
|
|
66896
68086
|
meta: {
|
|
66897
68087
|
name: "store",
|
|
66898
68088
|
description: "The connected Shopify store: currency, countries, how many products, what is out of stock. Example: baker shopify store"
|
|
@@ -66903,13 +68093,14 @@ var storeCommand = defineCommand211({
|
|
|
66903
68093
|
run: async ({ args: args5 }) => {
|
|
66904
68094
|
try {
|
|
66905
68095
|
const answer = await apiGet("/api/shopify/store", params({ full: args5.full }));
|
|
66906
|
-
|
|
68096
|
+
const data = answer.canChange ? { ...answer.summary, canChange: answer.canChange } : answer.summary;
|
|
68097
|
+
emit2(data, { store: answer.store }, [...storeStateHints(answer.store), ...storeHints(answer.summary)]);
|
|
66907
68098
|
} catch (err) {
|
|
66908
68099
|
fail9(err);
|
|
66909
68100
|
}
|
|
66910
68101
|
}
|
|
66911
68102
|
});
|
|
66912
|
-
var productsCommand =
|
|
68103
|
+
var productsCommand = defineCommand215({
|
|
66913
68104
|
meta: {
|
|
66914
68105
|
name: "products",
|
|
66915
68106
|
description: 'What the store sells, with price and stock. Example: baker shopify products --search "snowboard" --stock out_of_stock'
|
|
@@ -66955,7 +68146,7 @@ var productsCommand = defineCommand211({
|
|
|
66955
68146
|
}
|
|
66956
68147
|
}
|
|
66957
68148
|
});
|
|
66958
|
-
var productCommand =
|
|
68149
|
+
var productCommand = defineCommand215({
|
|
66959
68150
|
meta: {
|
|
66960
68151
|
name: "product",
|
|
66961
68152
|
description: "One product: options with buy links, prices by country, stock, photo imageIds, video playbackIds. Accepts an id, handle or link. Example: baker shopify product the-complete-snowboard --content"
|
|
@@ -66989,8 +68180,8 @@ var productCommand = defineCommand211({
|
|
|
66989
68180
|
},
|
|
66990
68181
|
run: async ({ args: args5 }) => {
|
|
66991
68182
|
try {
|
|
66992
|
-
const
|
|
66993
|
-
if (
|
|
68183
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
68184
|
+
if (positionals2.length > 1) {
|
|
66994
68185
|
throw new ApiError(
|
|
66995
68186
|
"VALIDATION_ERROR",
|
|
66996
68187
|
"ref: Pass one product id, handle or product link \u2014 quote a link, and search by words with `baker shopify products --search`."
|
|
@@ -67018,7 +68209,7 @@ var productCommand = defineCommand211({
|
|
|
67018
68209
|
}
|
|
67019
68210
|
}
|
|
67020
68211
|
});
|
|
67021
|
-
var collectionsCommand =
|
|
68212
|
+
var collectionsCommand = defineCommand215({
|
|
67022
68213
|
meta: {
|
|
67023
68214
|
name: "collections",
|
|
67024
68215
|
description: "The store's collections, with the handles --collection takes. Example: baker shopify collections --full"
|
|
@@ -67043,7 +68234,7 @@ var collectionsCommand = defineCommand211({
|
|
|
67043
68234
|
}
|
|
67044
68235
|
}
|
|
67045
68236
|
});
|
|
67046
|
-
var stockCommand2 =
|
|
68237
|
+
var stockCommand2 = defineCommand215({
|
|
67047
68238
|
meta: {
|
|
67048
68239
|
name: "stock",
|
|
67049
68240
|
description: "Every product with options out of stock, naming them. Example: baker shopify stock"
|
|
@@ -67067,12 +68258,12 @@ var stockCommand2 = defineCommand211({
|
|
|
67067
68258
|
}
|
|
67068
68259
|
}
|
|
67069
68260
|
});
|
|
67070
|
-
var shopifyCommand =
|
|
68261
|
+
var shopifyCommand = defineCommand215({
|
|
67071
68262
|
meta: {
|
|
67072
68263
|
name: "shopify",
|
|
67073
68264
|
description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections,
|
|
67074
|
-
product photos, what it sold, who buys, where and what, and what advertises each product
|
|
67075
|
-
|
|
68265
|
+
product photos, what it sold, who buys, where and what, and what advertises each product \u2014 and stage
|
|
68266
|
+
changes to it (\`change\`), applied when the user publishes the chat and undone with \`undo\`.
|
|
67076
68267
|
|
|
67077
68268
|
Examples:
|
|
67078
68269
|
baker shopify store # currency, countries, how many products, what is out of stock
|
|
@@ -67095,7 +68286,11 @@ Examples:
|
|
|
67095
68286
|
baker shopify segments # best, loyal, at risk, new, one-time \u2014 and who to find more of
|
|
67096
68287
|
baker shopify cohorts --months 12 # buyers by first-order month: who came back
|
|
67097
68288
|
baker shopify promotions <product> # what advertises it: ads, landings, Shopping (read before pausing)
|
|
67098
|
-
baker shopify stock-holds --product <product> # what Baker paused because it ran out,
|
|
68289
|
+
baker shopify stock-holds --product <product> # what Baker paused because it ran out: what to resume, what to tell the user
|
|
68290
|
+
baker shopify change product update <product> --title "\u2026" # stage a store change (product|variant|field|collection|discount|redirect|campaign|measurement)
|
|
68291
|
+
baker shopify draft list # the store changes staged on this chat
|
|
68292
|
+
baker shopify changes # what Baker changed in the store; baker shopify undo <changeId> puts one back
|
|
68293
|
+
baker shopify tracking audit # is the store measured right? (reads only)
|
|
67099
68294
|
|
|
67100
68295
|
Product photos are already in the image library: place them by imageId
|
|
67101
68296
|
(baker images download <imageIds> --out src/pages/<page>/_images/), never by a cdn.shopify.com link.
|
|
@@ -67120,15 +68315,20 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
|
67120
68315
|
cohorts: cohortsCommand,
|
|
67121
68316
|
segments: segmentsCommand,
|
|
67122
68317
|
promotions: promotionsCommand,
|
|
67123
|
-
"stock-holds": stockHoldsCommand
|
|
68318
|
+
"stock-holds": stockHoldsCommand,
|
|
68319
|
+
change: changeCommand,
|
|
68320
|
+
draft: draftCommand5,
|
|
68321
|
+
changes: changesCommand2,
|
|
68322
|
+
undo: undoCommand,
|
|
68323
|
+
tracking: trackingCommand2
|
|
67124
68324
|
}
|
|
67125
68325
|
});
|
|
67126
68326
|
|
|
67127
68327
|
// src/commands/studio/index.ts
|
|
67128
|
-
import { defineCommand as
|
|
68328
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
67129
68329
|
|
|
67130
68330
|
// src/commands/studio/animate.ts
|
|
67131
|
-
import { defineCommand as
|
|
68331
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
67132
68332
|
|
|
67133
68333
|
// src/commands/studio/spokenPace.ts
|
|
67134
68334
|
var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
|
|
@@ -67641,7 +68841,7 @@ async function adByHandHintFor(body) {
|
|
|
67641
68841
|
return null;
|
|
67642
68842
|
}
|
|
67643
68843
|
}
|
|
67644
|
-
var animateCommand =
|
|
68844
|
+
var animateCommand = defineCommand216({
|
|
67645
68845
|
meta: {
|
|
67646
68846
|
name: "animate",
|
|
67647
68847
|
description: "Render a clip. With an image the look is already fixed, so the prompt describes MOVEMENT \u2014 what the camera does, what the subject does, in what order. With --from text there is no image and the prompt is the whole shot.\n\nA rendered clip is NOT usable anywhere until you keep it: `baker studio keep <id> --slot N` is what puts it in the video library. Takes nobody keeps are never ingested, which is what makes a rejected batch cheap.\n\nFor anything longer than 15 seconds, or to build on footage that already exists, use --model bytedance/seedance-2.5: it renders 4-30s and is the only model that reads an existing clip or an existing soundtrack.\n\nExamples:\n baker studio animate 'slow push in, model turns to camera and smiles' --image j57abc123def456ghi789\n baker studio animate 'she looks to camera and says: \"Hola, soy Elena\"' --avatar elena --quality 720p --aspect-ratio 9:16\n baker studio animate 'handheld drift right, steam rising from the cup' --image './out/hero.png' --duration 6 --quality 1080p\n baker studio animate 'product rotates once on a turntable' --image j57abc\u2026,j57def\u2026 --from references\n baker studio animate 'she keeps walking, camera stays with her, then she stops and looks up' --image j57abc\u2026 --from references --from-clip j57batch\u2026:0 --model bytedance/seedance-2.5 --duration 20\n baker studio animate 'hold on the product, then a slow push-in' --from references --from-video j57vid\u2026 --model bytedance/seedance-2.5\n baker studio animate 'slow drone pull-back over a solar farm at golden hour, no people' --from text --model bytedance/seedance-2.5 --duration 12"
|
|
@@ -67766,7 +68966,7 @@ var animateCommand = defineCommand212({
|
|
|
67766
68966
|
});
|
|
67767
68967
|
|
|
67768
68968
|
// src/commands/studio/generate.ts
|
|
67769
|
-
import { defineCommand as
|
|
68969
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
67770
68970
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
67771
68971
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
67772
68972
|
registerSchema({
|
|
@@ -67902,7 +69102,7 @@ function buildGenerateBody(args5, prompt) {
|
|
|
67902
69102
|
}
|
|
67903
69103
|
return body;
|
|
67904
69104
|
}
|
|
67905
|
-
var generateCommand =
|
|
69105
|
+
var generateCommand = defineCommand217({
|
|
67906
69106
|
meta: {
|
|
67907
69107
|
name: "generate",
|
|
67908
69108
|
description: "Start here to make an image. Renders 1-8 takes of one brief, ingests each into the media library as it lands, and shows the batch in the dashboard Studio next to the ones the client ran.\n\nModel choice: google/gemini-3.1-flash-image-preview (default \u2014 fast, best at editing a reference and at extreme ratios), google/gemini-3-pro-image-preview (highest fidelity, slower), openai/gpt-image-2 (photoreal and the cleanest in-image text \u2014 no --image-size, no 4:5 / 5:4), recraft/recraft-v4.1-pro-vector (vector/flat marks with palette control).\n\n--reference is the biggest quality lever there is: a real logo, product shot, Pinterest pin or sandbox screenshot beats any amount of adjectives.\n\nExamples:\n baker studio generate 'matte black bottle on wet marble, hard studio light, 35mm' --aspect-ratio 3:2 --count 3\n baker studio generate 'this bottle on a sunlit kitchen counter' --reference './src/brand/product.png,https://\u2026/kitchen.jpg'\n baker studio generate 'founder-style selfie, kitchen background, natural light' --skill ugc-selfie-hook\n baker studio generate 'flat geometric mascot, brand palette' --model recraft/recraft-v4.1-pro-vector --rgb-colors '[[10,10,10],[255,80,0]]'"
|
|
@@ -67985,7 +69185,7 @@ var generateCommand = defineCommand213({
|
|
|
67985
69185
|
});
|
|
67986
69186
|
|
|
67987
69187
|
// src/commands/studio/get.ts
|
|
67988
|
-
import { defineCommand as
|
|
69188
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
67989
69189
|
registerSchema({
|
|
67990
69190
|
command: "studio.get",
|
|
67991
69191
|
description: "Read one Studio batch: every take, where it lives, and why a take is missing. This is how you pick up a batch that was still rendering when the start command returned.",
|
|
@@ -67994,7 +69194,7 @@ registerSchema({
|
|
|
67994
69194
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
67995
69195
|
}
|
|
67996
69196
|
});
|
|
67997
|
-
var getCommand5 =
|
|
69197
|
+
var getCommand5 = defineCommand218({
|
|
67998
69198
|
meta: {
|
|
67999
69199
|
name: "get",
|
|
68000
69200
|
description: "Read one Studio batch \u2014 the takes, their urls, whether each is in the library, and the reason for any that failed.\n\nExample: baker studio get j57abc123def456ghi789\nExample: baker studio get j57abc123def456ghi789 --full"
|
|
@@ -68023,7 +69223,7 @@ var getCommand5 = defineCommand214({
|
|
|
68023
69223
|
});
|
|
68024
69224
|
|
|
68025
69225
|
// src/commands/studio/improve.ts
|
|
68026
|
-
import { defineCommand as
|
|
69226
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
68027
69227
|
var DESCRIPTION2 = "Sharpen a rough brief into directed art direction \u2014 the same rewrite the client gets from the wand in the Studio prompt bar. Reach for it when you are relaying the CLIENT's own words and want them shaped without substituting your voice; when you are writing the art direction yourself, just write it, because you will do a better job than this does.";
|
|
68028
69228
|
registerSchema({
|
|
68029
69229
|
command: "studio.improve",
|
|
@@ -68048,7 +69248,7 @@ registerSchema({
|
|
|
68048
69248
|
}
|
|
68049
69249
|
}
|
|
68050
69250
|
});
|
|
68051
|
-
var improveCommand =
|
|
69251
|
+
var improveCommand = defineCommand219({
|
|
68052
69252
|
meta: {
|
|
68053
69253
|
name: "improve",
|
|
68054
69254
|
description: `${DESCRIPTION2}
|
|
@@ -68092,7 +69292,7 @@ Examples:
|
|
|
68092
69292
|
});
|
|
68093
69293
|
|
|
68094
69294
|
// src/commands/studio/keep.ts
|
|
68095
|
-
import { defineCommand as
|
|
69295
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
68096
69296
|
registerSchema({
|
|
68097
69297
|
command: "studio.keep",
|
|
68098
69298
|
description: "Mark one take as the keeper. For an image this stars it, so the client reviewing the batch sees which one you used. For a CLIP it is the step that puts it in the video library \u2014 until then the clip cannot be used in a canvas, a landing, or an ad.",
|
|
@@ -68102,7 +69302,7 @@ registerSchema({
|
|
|
68102
69302
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
68103
69303
|
}
|
|
68104
69304
|
});
|
|
68105
|
-
var keepCommand =
|
|
69305
|
+
var keepCommand = defineCommand220({
|
|
68106
69306
|
meta: {
|
|
68107
69307
|
name: "keep",
|
|
68108
69308
|
description: "Mark one take as the keeper. An image gets starred (it was already in the library); a clip gets INGESTED into the video library, which is what makes it usable anywhere else.\n\nExample: baker studio keep j57abc123def456ghi789 --slot 2\nExample: baker studio keep j57abc123def456ghi789 --slot 2 --undo"
|
|
@@ -68153,7 +69353,7 @@ var keepCommand = defineCommand216({
|
|
|
68153
69353
|
});
|
|
68154
69354
|
|
|
68155
69355
|
// src/commands/studio/list.ts
|
|
68156
|
-
import { defineCommand as
|
|
69356
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
68157
69357
|
registerSchema({
|
|
68158
69358
|
command: "studio.list",
|
|
68159
69359
|
description: "Recent Studio batches for THIS conversation, newest first \u2014 what you have already generated, so you re-use a take instead of paying for it twice. `--all` widens it to everything the company generated, including what people ran themselves in the dashboard.",
|
|
@@ -68164,7 +69364,7 @@ registerSchema({
|
|
|
68164
69364
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
68165
69365
|
}
|
|
68166
69366
|
});
|
|
68167
|
-
var listCommand18 =
|
|
69367
|
+
var listCommand18 = defineCommand221({
|
|
68168
69368
|
meta: {
|
|
68169
69369
|
name: "list",
|
|
68170
69370
|
description: "Recent Studio batches, newest first. Scoped to this conversation unless you pass --all.\n\nExample: baker studio list\nExample: baker studio list --kind video --limit 5\nExample: baker studio list --all # includes batches the client ran in the dashboard"
|
|
@@ -68198,7 +69398,7 @@ var listCommand18 = defineCommand217({
|
|
|
68198
69398
|
});
|
|
68199
69399
|
|
|
68200
69400
|
// src/commands/studio/models.ts
|
|
68201
|
-
import { defineCommand as
|
|
69401
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
68202
69402
|
var DESCRIPTION3 = "What each Studio model actually accepts: its shapes, resolutions, clip lengths, prompt character cap, how many reference images it takes, and which knobs it has. Read this before a batch you care about \u2014 the models disagree far more than they look like they do, and a setting the chosen model does not have is REFUSED, not ignored.";
|
|
68203
69403
|
registerSchema({
|
|
68204
69404
|
command: "studio.models",
|
|
@@ -68285,7 +69485,7 @@ function buildModelCards(kind, model) {
|
|
|
68285
69485
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
68286
69486
|
return selected.map((id) => build(id));
|
|
68287
69487
|
}
|
|
68288
|
-
var modelsCommand =
|
|
69488
|
+
var modelsCommand = defineCommand222({
|
|
68289
69489
|
meta: {
|
|
68290
69490
|
name: "models",
|
|
68291
69491
|
description: `${DESCRIPTION3}
|
|
@@ -68332,13 +69532,13 @@ Examples:
|
|
|
68332
69532
|
});
|
|
68333
69533
|
|
|
68334
69534
|
// src/commands/studio/skills.ts
|
|
68335
|
-
import { defineCommand as
|
|
69535
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
68336
69536
|
registerSchema({
|
|
68337
69537
|
command: "studio.skills",
|
|
68338
69538
|
description: "The craft directions `studio generate --skill <id>` accepts. Each one carries directed art direction plus the model, shape and take count it wants, so you pick a look by name instead of writing the boilerplate yourself.",
|
|
68339
69539
|
args: {}
|
|
68340
69540
|
});
|
|
68341
|
-
var skillsCommand =
|
|
69541
|
+
var skillsCommand = defineCommand223({
|
|
68342
69542
|
meta: {
|
|
68343
69543
|
name: "skills",
|
|
68344
69544
|
description: "List the craft directions available to `baker studio generate --skill <id>` \u2014 what each one is for, whether it wants a reference image, and the model/shape/count it defaults to.\n\nExample: baker studio skills"
|
|
@@ -68362,7 +69562,7 @@ var skillsCommand = defineCommand219({
|
|
|
68362
69562
|
});
|
|
68363
69563
|
|
|
68364
69564
|
// src/commands/studio/index.ts
|
|
68365
|
-
var studioCommand =
|
|
69565
|
+
var studioCommand = defineCommand224({
|
|
68366
69566
|
meta: {
|
|
68367
69567
|
name: "studio",
|
|
68368
69568
|
description: `Make new imagery and clips. Every batch is recorded and shows up in the dashboard Studio for the client to review, labelled with this conversation.
|
|
@@ -68405,10 +69605,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
68405
69605
|
});
|
|
68406
69606
|
|
|
68407
69607
|
// src/commands/tag-manager/index.ts
|
|
68408
|
-
import { defineCommand as
|
|
69608
|
+
import { defineCommand as defineCommand228 } from "citty";
|
|
68409
69609
|
|
|
68410
69610
|
// src/commands/tag-manager/draft.ts
|
|
68411
|
-
import { defineCommand as
|
|
69611
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
68412
69612
|
|
|
68413
69613
|
// src/commands/tag-manager/shared.ts
|
|
68414
69614
|
import { readFileSync as readFileSync20 } from "fs";
|
|
@@ -68418,11 +69618,11 @@ function failValidation5(message) {
|
|
|
68418
69618
|
}
|
|
68419
69619
|
function requireTarget6(args5, entity) {
|
|
68420
69620
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
68421
|
-
const
|
|
68422
|
-
if (typeof
|
|
69621
|
+
const target4 = args5.id ?? args5.target ?? positional;
|
|
69622
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
68423
69623
|
failValidation5(`pass the ${entity} id or path as the positional argument`);
|
|
68424
69624
|
}
|
|
68425
|
-
return
|
|
69625
|
+
return target4;
|
|
68426
69626
|
}
|
|
68427
69627
|
function loadJsonArg2(args5, flag3 = "json") {
|
|
68428
69628
|
const inline = args5[flag3];
|
|
@@ -68531,13 +69731,13 @@ registerSchema({
|
|
|
68531
69731
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
68532
69732
|
}
|
|
68533
69733
|
});
|
|
68534
|
-
var
|
|
69734
|
+
var draftCommand6 = defineCommand225({
|
|
68535
69735
|
meta: {
|
|
68536
69736
|
name: "draft",
|
|
68537
69737
|
description: "List, show, amend, remove, or clear staged Tag Manager changes for this chat. `list` and `show` take --chat <id> to read an earlier chat's changes instead."
|
|
68538
69738
|
},
|
|
68539
69739
|
subCommands: {
|
|
68540
|
-
list:
|
|
69740
|
+
list: defineCommand225({
|
|
68541
69741
|
meta: {
|
|
68542
69742
|
name: "list",
|
|
68543
69743
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -68550,7 +69750,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68550
69750
|
await draftList2(args5.json === true, args5.chat);
|
|
68551
69751
|
}
|
|
68552
69752
|
}),
|
|
68553
|
-
show:
|
|
69753
|
+
show: defineCommand225({
|
|
68554
69754
|
meta: {
|
|
68555
69755
|
name: "show",
|
|
68556
69756
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -68567,7 +69767,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68567
69767
|
);
|
|
68568
69768
|
}
|
|
68569
69769
|
}),
|
|
68570
|
-
amend:
|
|
69770
|
+
amend: defineCommand225({
|
|
68571
69771
|
meta: {
|
|
68572
69772
|
name: "amend",
|
|
68573
69773
|
description: "Update a staged change in place \u2014 merges a JSON patch into its payload (objects deep-merge, null deletes a key, arrays/scalars replace) and re-validates. Use this instead of remove + re-create."
|
|
@@ -68584,7 +69784,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68584
69784
|
});
|
|
68585
69785
|
}
|
|
68586
69786
|
}),
|
|
68587
|
-
remove:
|
|
69787
|
+
remove: defineCommand225({
|
|
68588
69788
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
68589
69789
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
68590
69790
|
run: async ({ args: args5 }) => {
|
|
@@ -68593,7 +69793,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68593
69793
|
});
|
|
68594
69794
|
}
|
|
68595
69795
|
}),
|
|
68596
|
-
clear:
|
|
69796
|
+
clear: defineCommand225({
|
|
68597
69797
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
68598
69798
|
run: async () => {
|
|
68599
69799
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -68603,7 +69803,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68603
69803
|
});
|
|
68604
69804
|
|
|
68605
69805
|
// src/commands/tag-manager/read.ts
|
|
68606
|
-
import { defineCommand as
|
|
69806
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
68607
69807
|
registerSchema({
|
|
68608
69808
|
command: "tagManager.containers",
|
|
68609
69809
|
description: "List the Google Tag Manager containers this company's connection can reach. Every container the company connected is flagged `connected: true` \u2014 there can be several, and Baker may read and change all of them. Start here to confirm which containers you are managing.",
|
|
@@ -68644,7 +69844,7 @@ function containersHints(containers) {
|
|
|
68644
69844
|
}))
|
|
68645
69845
|
});
|
|
68646
69846
|
}
|
|
68647
|
-
var containersCommand =
|
|
69847
|
+
var containersCommand = defineCommand226({
|
|
68648
69848
|
meta: {
|
|
68649
69849
|
name: "containers",
|
|
68650
69850
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -68661,7 +69861,7 @@ Start here:
|
|
|
68661
69861
|
}
|
|
68662
69862
|
}
|
|
68663
69863
|
});
|
|
68664
|
-
var readCommand =
|
|
69864
|
+
var readCommand = defineCommand226({
|
|
68665
69865
|
meta: {
|
|
68666
69866
|
name: "read",
|
|
68667
69867
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -68703,7 +69903,7 @@ Examples:
|
|
|
68703
69903
|
});
|
|
68704
69904
|
|
|
68705
69905
|
// src/commands/tag-manager/write-commands.ts
|
|
68706
|
-
import { defineCommand as
|
|
69906
|
+
import { defineCommand as defineCommand227 } from "citty";
|
|
68707
69907
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
68708
69908
|
var ENTITIES = [
|
|
68709
69909
|
{
|
|
@@ -68759,10 +69959,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
68759
69959
|
});
|
|
68760
69960
|
}
|
|
68761
69961
|
function entityCommand(entity, noun, example) {
|
|
68762
|
-
return
|
|
69962
|
+
return defineCommand227({
|
|
68763
69963
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
68764
69964
|
subCommands: {
|
|
68765
|
-
create:
|
|
69965
|
+
create: defineCommand227({
|
|
68766
69966
|
meta: {
|
|
68767
69967
|
name: "create",
|
|
68768
69968
|
description: `Stage a new ${noun}
|
|
@@ -68784,7 +69984,7 @@ Examples:
|
|
|
68784
69984
|
});
|
|
68785
69985
|
}
|
|
68786
69986
|
}),
|
|
68787
|
-
update:
|
|
69987
|
+
update: defineCommand227({
|
|
68788
69988
|
meta: {
|
|
68789
69989
|
name: "update",
|
|
68790
69990
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -68804,7 +70004,7 @@ Examples:
|
|
|
68804
70004
|
});
|
|
68805
70005
|
}
|
|
68806
70006
|
}),
|
|
68807
|
-
delete:
|
|
70007
|
+
delete: defineCommand227({
|
|
68808
70008
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
68809
70009
|
args: {
|
|
68810
70010
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -68845,7 +70045,7 @@ function builtinTypes(args5) {
|
|
|
68845
70045
|
}
|
|
68846
70046
|
return raw.split(",").map((entry) => entry.trim());
|
|
68847
70047
|
}
|
|
68848
|
-
var builtinCommand =
|
|
70048
|
+
var builtinCommand = defineCommand227({
|
|
68849
70049
|
meta: {
|
|
68850
70050
|
name: "builtin",
|
|
68851
70051
|
description: `Enable or disable built-in variables
|
|
@@ -68855,7 +70055,7 @@ Examples:
|
|
|
68855
70055
|
baker tag-manager builtin disable --types formId`
|
|
68856
70056
|
},
|
|
68857
70057
|
subCommands: {
|
|
68858
|
-
enable:
|
|
70058
|
+
enable: defineCommand227({
|
|
68859
70059
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
68860
70060
|
args: {
|
|
68861
70061
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -68869,7 +70069,7 @@ Examples:
|
|
|
68869
70069
|
});
|
|
68870
70070
|
}
|
|
68871
70071
|
}),
|
|
68872
|
-
disable:
|
|
70072
|
+
disable: defineCommand227({
|
|
68873
70073
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
68874
70074
|
args: {
|
|
68875
70075
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -68887,7 +70087,7 @@ Examples:
|
|
|
68887
70087
|
});
|
|
68888
70088
|
|
|
68889
70089
|
// src/commands/tag-manager/index.ts
|
|
68890
|
-
var tagManagerCommand =
|
|
70090
|
+
var tagManagerCommand = defineCommand228({
|
|
68891
70091
|
meta: {
|
|
68892
70092
|
name: "tag-manager",
|
|
68893
70093
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -68919,12 +70119,12 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
68919
70119
|
variable: variableCommand,
|
|
68920
70120
|
folder: folderCommand,
|
|
68921
70121
|
builtin: builtinCommand,
|
|
68922
|
-
draft:
|
|
70122
|
+
draft: draftCommand6
|
|
68923
70123
|
}
|
|
68924
70124
|
});
|
|
68925
70125
|
|
|
68926
70126
|
// src/commands/tags/index.ts
|
|
68927
|
-
import { defineCommand as
|
|
70127
|
+
import { defineCommand as defineCommand229 } from "citty";
|
|
68928
70128
|
|
|
68929
70129
|
// src/commands/tags/shared.ts
|
|
68930
70130
|
function failApi3(err) {
|
|
@@ -69004,7 +70204,7 @@ async function listTags(json) {
|
|
|
69004
70204
|
var listArgs11 = {
|
|
69005
70205
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
69006
70206
|
};
|
|
69007
|
-
var listCommand19 =
|
|
70207
|
+
var listCommand19 = defineCommand229({
|
|
69008
70208
|
meta: {
|
|
69009
70209
|
name: "list",
|
|
69010
70210
|
description: "Effective tags for this chat (production + staged), with each tag's full readable config (secrets excluded) \u2014 reuse a stored value to pre-fill a change rather than asking the user. Refs printed here are what flow side-effect tagIds should use. Example: baker tags list"
|
|
@@ -69023,7 +70223,7 @@ async function listDraft4(chat) {
|
|
|
69023
70223
|
failApi3(err);
|
|
69024
70224
|
}
|
|
69025
70225
|
}
|
|
69026
|
-
var
|
|
70226
|
+
var draftCommand7 = defineCommand229({
|
|
69027
70227
|
meta: {
|
|
69028
70228
|
name: "draft",
|
|
69029
70229
|
description: "Review the tag changes staged in this chat (read-only). Staged changes were approved via request_tag_input and apply when the chat is published; to amend or drop one, propose a follow-up change through the same tool (a delete on a tag_temp_* ref drops the staged create). Takes --chat <id> to read an earlier chat's staged changes instead."
|
|
@@ -69033,7 +70233,7 @@ var draftCommand6 = defineCommand225({
|
|
|
69033
70233
|
await listDraft4(args5.chat);
|
|
69034
70234
|
}
|
|
69035
70235
|
});
|
|
69036
|
-
var tagsCommand4 =
|
|
70236
|
+
var tagsCommand4 = defineCommand229({
|
|
69037
70237
|
meta: {
|
|
69038
70238
|
name: "tags",
|
|
69039
70239
|
description: `Read the client's marketing/analytics tags (Meta pixel, GA4, Google Ads, GTM, Clarity, Hotjar, \u2026) \u2014 production tags plus the changes staged in this chat.
|
|
@@ -69051,7 +70251,7 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
69051
70251
|
},
|
|
69052
70252
|
subCommands: {
|
|
69053
70253
|
list: listCommand19,
|
|
69054
|
-
draft:
|
|
70254
|
+
draft: draftCommand7
|
|
69055
70255
|
},
|
|
69056
70256
|
// Bare `baker tags` lists the effective tags. `args` stays so citty knows this
|
|
69057
70257
|
// command's flags when it scans rawArgs for a subcommand name, and `default` (not
|
|
@@ -69062,10 +70262,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
69062
70262
|
});
|
|
69063
70263
|
|
|
69064
70264
|
// src/commands/testimonials/index.ts
|
|
69065
|
-
import { defineCommand as
|
|
70265
|
+
import { defineCommand as defineCommand233 } from "citty";
|
|
69066
70266
|
|
|
69067
70267
|
// src/commands/testimonials/get.ts
|
|
69068
|
-
import { defineCommand as
|
|
70268
|
+
import { defineCommand as defineCommand230 } from "citty";
|
|
69069
70269
|
registerSchema({
|
|
69070
70270
|
command: "testimonials.get",
|
|
69071
70271
|
description: "Get a single testimonial by ID",
|
|
@@ -69073,7 +70273,7 @@ registerSchema({
|
|
|
69073
70273
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
69074
70274
|
}
|
|
69075
70275
|
});
|
|
69076
|
-
var getCommand6 =
|
|
70276
|
+
var getCommand6 = defineCommand230({
|
|
69077
70277
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
69078
70278
|
args: {
|
|
69079
70279
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -69110,7 +70310,7 @@ var getCommand6 = defineCommand226({
|
|
|
69110
70310
|
});
|
|
69111
70311
|
|
|
69112
70312
|
// src/commands/testimonials/list.ts
|
|
69113
|
-
import { defineCommand as
|
|
70313
|
+
import { defineCommand as defineCommand231 } from "citty";
|
|
69114
70314
|
|
|
69115
70315
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
69116
70316
|
function resolveEmptyReason({
|
|
@@ -69267,7 +70467,7 @@ function buildListParams(args5) {
|
|
|
69267
70467
|
}
|
|
69268
70468
|
return params2;
|
|
69269
70469
|
}
|
|
69270
|
-
var listCommand20 =
|
|
70470
|
+
var listCommand20 = defineCommand231({
|
|
69271
70471
|
meta: {
|
|
69272
70472
|
name: "list",
|
|
69273
70473
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -69327,7 +70527,7 @@ var listCommand20 = defineCommand227({
|
|
|
69327
70527
|
});
|
|
69328
70528
|
|
|
69329
70529
|
// src/commands/testimonials/search.ts
|
|
69330
|
-
import { defineCommand as
|
|
70530
|
+
import { defineCommand as defineCommand232 } from "citty";
|
|
69331
70531
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
69332
70532
|
function languageBiasHint(results, requestedLanguage) {
|
|
69333
70533
|
if (requestedLanguage) {
|
|
@@ -69406,7 +70606,7 @@ function buildSearchRequest(query, args5) {
|
|
|
69406
70606
|
}
|
|
69407
70607
|
return body;
|
|
69408
70608
|
}
|
|
69409
|
-
var searchCommand3 =
|
|
70609
|
+
var searchCommand3 = defineCommand232({
|
|
69410
70610
|
meta: {
|
|
69411
70611
|
name: "search",
|
|
69412
70612
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -69470,7 +70670,7 @@ var searchCommand3 = defineCommand228({
|
|
|
69470
70670
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
69471
70671
|
|
|
69472
70672
|
// src/commands/testimonials/index.ts
|
|
69473
|
-
var testimonialsCommand =
|
|
70673
|
+
var testimonialsCommand = defineCommand233({
|
|
69474
70674
|
meta: {
|
|
69475
70675
|
name: "testimonials",
|
|
69476
70676
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -69492,10 +70692,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
69492
70692
|
});
|
|
69493
70693
|
|
|
69494
70694
|
// src/commands/videos/index.ts
|
|
69495
|
-
import { defineCommand as
|
|
70695
|
+
import { defineCommand as defineCommand241 } from "citty";
|
|
69496
70696
|
|
|
69497
70697
|
// src/commands/videos/delete.ts
|
|
69498
|
-
import { defineCommand as
|
|
70698
|
+
import { defineCommand as defineCommand234 } from "citty";
|
|
69499
70699
|
registerSchema({
|
|
69500
70700
|
command: "videos.delete",
|
|
69501
70701
|
description: "Delete a video by ID",
|
|
@@ -69509,7 +70709,7 @@ registerSchema({
|
|
|
69509
70709
|
}
|
|
69510
70710
|
}
|
|
69511
70711
|
});
|
|
69512
|
-
var deleteCommand4 =
|
|
70712
|
+
var deleteCommand4 = defineCommand234({
|
|
69513
70713
|
meta: {
|
|
69514
70714
|
name: "delete",
|
|
69515
70715
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -69550,7 +70750,7 @@ var deleteCommand4 = defineCommand230({
|
|
|
69550
70750
|
});
|
|
69551
70751
|
|
|
69552
70752
|
// src/commands/videos/describe.ts
|
|
69553
|
-
import { defineCommand as
|
|
70753
|
+
import { defineCommand as defineCommand235 } from "citty";
|
|
69554
70754
|
var DESCRIPTION_HELP2 = "What the clip actually shows, in the words someone would search for it by. This is what `baker videos search` retrieves on.";
|
|
69555
70755
|
registerSchema({
|
|
69556
70756
|
command: "videos.describe",
|
|
@@ -69567,7 +70767,7 @@ registerSchema({
|
|
|
69567
70767
|
full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
|
|
69568
70768
|
}
|
|
69569
70769
|
});
|
|
69570
|
-
var describeCommand2 =
|
|
70770
|
+
var describeCommand2 = defineCommand235({
|
|
69571
70771
|
meta: {
|
|
69572
70772
|
name: "describe",
|
|
69573
70773
|
description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
|
|
@@ -69625,7 +70825,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
69625
70825
|
});
|
|
69626
70826
|
|
|
69627
70827
|
// src/commands/videos/get.ts
|
|
69628
|
-
import { defineCommand as
|
|
70828
|
+
import { defineCommand as defineCommand236 } from "citty";
|
|
69629
70829
|
registerSchema({
|
|
69630
70830
|
command: "videos.get",
|
|
69631
70831
|
description: "Get a single video by ID",
|
|
@@ -69633,7 +70833,7 @@ registerSchema({
|
|
|
69633
70833
|
id: { type: "string", description: "Video ID", required: true }
|
|
69634
70834
|
}
|
|
69635
70835
|
});
|
|
69636
|
-
var getCommand7 =
|
|
70836
|
+
var getCommand7 = defineCommand236({
|
|
69637
70837
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
69638
70838
|
args: {
|
|
69639
70839
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -69670,7 +70870,7 @@ var getCommand7 = defineCommand232({
|
|
|
69670
70870
|
});
|
|
69671
70871
|
|
|
69672
70872
|
// src/commands/videos/group.ts
|
|
69673
|
-
import { defineCommand as
|
|
70873
|
+
import { defineCommand as defineCommand237 } from "citty";
|
|
69674
70874
|
registerSchema({
|
|
69675
70875
|
command: "videos.group",
|
|
69676
70876
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -69679,7 +70879,7 @@ registerSchema({
|
|
|
69679
70879
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
69680
70880
|
}
|
|
69681
70881
|
});
|
|
69682
|
-
var groupCommand2 =
|
|
70882
|
+
var groupCommand2 = defineCommand237({
|
|
69683
70883
|
meta: {
|
|
69684
70884
|
name: "group",
|
|
69685
70885
|
description: "List every asset that arrived in the same set as this clip \u2014 the other slides of the Instagram post it came from, stills included. A carousel is authored to be read in order, so a clip pulled out of one is usually missing half its meaning. Example: baker videos group <videoId>"
|
|
@@ -69702,7 +70902,7 @@ var groupCommand2 = defineCommand233({
|
|
|
69702
70902
|
import { mkdtemp as mkdtemp3, rm as rm9, stat as stat12 } from "fs/promises";
|
|
69703
70903
|
import { tmpdir as tmpdir4 } from "os";
|
|
69704
70904
|
import path48 from "path";
|
|
69705
|
-
import { defineCommand as
|
|
70905
|
+
import { defineCommand as defineCommand238 } from "citty";
|
|
69706
70906
|
|
|
69707
70907
|
// src/lib/streamUpload.ts
|
|
69708
70908
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -69866,7 +71066,7 @@ registerSchema({
|
|
|
69866
71066
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
69867
71067
|
}
|
|
69868
71068
|
});
|
|
69869
|
-
var ingestCommand2 =
|
|
71069
|
+
var ingestCommand2 = defineCommand238({
|
|
69870
71070
|
meta: {
|
|
69871
71071
|
name: "ingest",
|
|
69872
71072
|
description: "Add a video to the library from a URL. A direct file URL is handed straight to Baker, which fetches it. A page URL (YouTube, TikTok, Vimeo, Instagram) is downloaded here first, then uploaded \u2014 and a direct URL that Baker cannot fetch falls back to that same path automatically.\n\nExample: baker videos ingest https://www.youtube.com/watch?v=abc123"
|
|
@@ -70128,7 +71328,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
70128
71328
|
}
|
|
70129
71329
|
|
|
70130
71330
|
// src/commands/videos/search.ts
|
|
70131
|
-
import { defineCommand as
|
|
71331
|
+
import { defineCommand as defineCommand239 } from "citty";
|
|
70132
71332
|
registerSchema({
|
|
70133
71333
|
command: "videos.search",
|
|
70134
71334
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -70138,7 +71338,7 @@ registerSchema({
|
|
|
70138
71338
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
70139
71339
|
}
|
|
70140
71340
|
});
|
|
70141
|
-
var searchCommand4 =
|
|
71341
|
+
var searchCommand4 = defineCommand239({
|
|
70142
71342
|
meta: {
|
|
70143
71343
|
name: "search",
|
|
70144
71344
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -70190,7 +71390,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
70190
71390
|
// src/commands/videos/upload.ts
|
|
70191
71391
|
import { readFile as readFile34, stat as stat13 } from "fs/promises";
|
|
70192
71392
|
import { basename as basename3, extname as extname4 } from "path";
|
|
70193
|
-
import { defineCommand as
|
|
71393
|
+
import { defineCommand as defineCommand240 } from "citty";
|
|
70194
71394
|
var MIME_MAP = {
|
|
70195
71395
|
".mp4": "video/mp4",
|
|
70196
71396
|
".mov": "video/quicktime",
|
|
@@ -70232,7 +71432,7 @@ function detectContentType(filePath) {
|
|
|
70232
71432
|
function isRemoteUrl3(value) {
|
|
70233
71433
|
return /^https?:\/\//i.test(value);
|
|
70234
71434
|
}
|
|
70235
|
-
var uploadCommand2 =
|
|
71435
|
+
var uploadCommand2 = defineCommand240({
|
|
70236
71436
|
meta: {
|
|
70237
71437
|
name: "upload",
|
|
70238
71438
|
description: "Upload a video to Baker \u2014 accepts a local file path OR a remote http(s) URL.\n\nLocal: auto-detects content type and uploads via Mux direct upload.\nRemote: hands off to `videos ingest` (direct fetch, or download-then-upload for a YouTube/TikTok/Vimeo page).\n\nExamples:\n baker videos upload ./demo.mp4\n baker videos upload https://www.youtube.com/watch?v=abc123"
|
|
@@ -70316,7 +71516,7 @@ var uploadCommand2 = defineCommand236({
|
|
|
70316
71516
|
});
|
|
70317
71517
|
|
|
70318
71518
|
// src/commands/videos/index.ts
|
|
70319
|
-
var videosCommand =
|
|
71519
|
+
var videosCommand = defineCommand241({
|
|
70320
71520
|
meta: {
|
|
70321
71521
|
name: "videos",
|
|
70322
71522
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
|
|
@@ -70345,10 +71545,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
70345
71545
|
});
|
|
70346
71546
|
|
|
70347
71547
|
// src/commands/winning-ads/index.ts
|
|
70348
|
-
import { defineCommand as
|
|
71548
|
+
import { defineCommand as defineCommand254 } from "citty";
|
|
70349
71549
|
|
|
70350
71550
|
// src/commands/winning-ads/advertisers.ts
|
|
70351
|
-
import { defineCommand as
|
|
71551
|
+
import { defineCommand as defineCommand242 } from "citty";
|
|
70352
71552
|
|
|
70353
71553
|
// src/commands/winning-ads/shared.ts
|
|
70354
71554
|
function splitList3(value) {
|
|
@@ -70401,7 +71601,7 @@ function advertiserNormalizer(record, full) {
|
|
|
70401
71601
|
last_synced_at: record.last_synced_at ?? null
|
|
70402
71602
|
};
|
|
70403
71603
|
}
|
|
70404
|
-
var advertisersCommand2 =
|
|
71604
|
+
var advertisersCommand2 = defineCommand242({
|
|
70405
71605
|
meta: {
|
|
70406
71606
|
name: "advertisers",
|
|
70407
71607
|
description: 'List corpus advertisers by name or domain. Find your own advertiser for --exclude-advertiser, or a competitor for --advertiser-id / winners. Example: baker winning-ads advertisers "Deel" --output md'
|
|
@@ -70459,7 +71659,7 @@ var advertisersCommand2 = defineCommand238({
|
|
|
70459
71659
|
});
|
|
70460
71660
|
|
|
70461
71661
|
// src/commands/winning-ads/brief.ts
|
|
70462
|
-
import { defineCommand as
|
|
71662
|
+
import { defineCommand as defineCommand243 } from "citty";
|
|
70463
71663
|
registerSchema({
|
|
70464
71664
|
command: "winning-ads.brief",
|
|
70465
71665
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -70505,7 +71705,7 @@ function parseDna(raw) {
|
|
|
70505
71705
|
}
|
|
70506
71706
|
return parsed;
|
|
70507
71707
|
}
|
|
70508
|
-
var briefCommand =
|
|
71708
|
+
var briefCommand = defineCommand243({
|
|
70509
71709
|
meta: {
|
|
70510
71710
|
name: "brief",
|
|
70511
71711
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -70541,7 +71741,7 @@ var briefCommand = defineCommand239({
|
|
|
70541
71741
|
});
|
|
70542
71742
|
|
|
70543
71743
|
// src/commands/winning-ads/content.ts
|
|
70544
|
-
import { defineCommand as
|
|
71744
|
+
import { defineCommand as defineCommand244 } from "citty";
|
|
70545
71745
|
registerSchema({
|
|
70546
71746
|
command: "winning-ads.content",
|
|
70547
71747
|
description: "Read what's INSIDE one winning ad: the spoken transcript, the on-screen text, and the ad copy. Use this after `search`/`winners`/`feed` return a shortlist \u2014 pass an ad_id to understand a reference before reproducing it. Add --full for speech, pacing, and soundtrack detail. Video ads carry the transcript/on-screen text; static ads carry only the copy.",
|
|
@@ -70554,7 +71754,7 @@ registerSchema({
|
|
|
70554
71754
|
}
|
|
70555
71755
|
}
|
|
70556
71756
|
});
|
|
70557
|
-
var contentCommand =
|
|
71757
|
+
var contentCommand = defineCommand244({
|
|
70558
71758
|
meta: {
|
|
70559
71759
|
name: "content",
|
|
70560
71760
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -70603,7 +71803,7 @@ var contentCommand = defineCommand240({
|
|
|
70603
71803
|
});
|
|
70604
71804
|
|
|
70605
71805
|
// src/commands/winning-ads/feed.ts
|
|
70606
|
-
import { defineCommand as
|
|
71806
|
+
import { defineCommand as defineCommand245 } from "citty";
|
|
70607
71807
|
function buildFeedParams(input) {
|
|
70608
71808
|
const params2 = {};
|
|
70609
71809
|
const advertiser = splitList3(input.advertiser);
|
|
@@ -70655,7 +71855,7 @@ registerSchema({
|
|
|
70655
71855
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
70656
71856
|
}
|
|
70657
71857
|
});
|
|
70658
|
-
var feedCommand2 =
|
|
71858
|
+
var feedCommand2 = defineCommand245({
|
|
70659
71859
|
meta: {
|
|
70660
71860
|
name: "feed",
|
|
70661
71861
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -70740,7 +71940,7 @@ var feedCommand2 = defineCommand241({
|
|
|
70740
71940
|
});
|
|
70741
71941
|
|
|
70742
71942
|
// src/commands/winning-ads/follow.ts
|
|
70743
|
-
import { defineCommand as
|
|
71943
|
+
import { defineCommand as defineCommand246 } from "citty";
|
|
70744
71944
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
70745
71945
|
registerSchema({
|
|
70746
71946
|
command: "winning-ads.follow",
|
|
@@ -70755,7 +71955,7 @@ registerSchema({
|
|
|
70755
71955
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
70756
71956
|
}
|
|
70757
71957
|
});
|
|
70758
|
-
var followCommand =
|
|
71958
|
+
var followCommand = defineCommand246({
|
|
70759
71959
|
meta: {
|
|
70760
71960
|
name: "follow",
|
|
70761
71961
|
description: 'Follow a brand to track ALL its ads \u2014 every platform and country. --platform is how we read your input, not a limit. A domain tracks every platform we can resolve. Example: baker winning-ads follow "deel.com" --platform meta'
|
|
@@ -70802,7 +72002,7 @@ var followCommand = defineCommand242({
|
|
|
70802
72002
|
});
|
|
70803
72003
|
|
|
70804
72004
|
// src/commands/winning-ads/follow-competitors.ts
|
|
70805
|
-
import { defineCommand as
|
|
72005
|
+
import { defineCommand as defineCommand247 } from "citty";
|
|
70806
72006
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
70807
72007
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
70808
72008
|
function buildFollowBatchBody(input) {
|
|
@@ -70835,7 +72035,7 @@ registerSchema({
|
|
|
70835
72035
|
}
|
|
70836
72036
|
}
|
|
70837
72037
|
});
|
|
70838
|
-
var followCompetitorsCommand =
|
|
72038
|
+
var followCompetitorsCommand = defineCommand247({
|
|
70839
72039
|
meta: {
|
|
70840
72040
|
name: "follow-competitors",
|
|
70841
72041
|
description: 'Follow many brands at once by domain \u2014 add every competitor in one call. Example: baker winning-ads follow-competitors "deel.com,notion.so,hubspot.com"'
|
|
@@ -70910,7 +72110,7 @@ var followCompetitorsCommand = defineCommand243({
|
|
|
70910
72110
|
});
|
|
70911
72111
|
|
|
70912
72112
|
// src/commands/winning-ads/following.ts
|
|
70913
|
-
import { defineCommand as
|
|
72113
|
+
import { defineCommand as defineCommand248 } from "citty";
|
|
70914
72114
|
registerSchema({
|
|
70915
72115
|
command: "winning-ads.following",
|
|
70916
72116
|
description: "List the brands you follow in your ad-dna library, with each one's status (ready vs still adding) and cached ad counts. A brand still adding has counts that are a lie in progress; one with `discovery_failed` has counts that are short because we couldn't finish looking, which is not the same as it running no ads.",
|
|
@@ -70964,7 +72164,7 @@ function followingNormalizer(record, full) {
|
|
|
70964
72164
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
70965
72165
|
};
|
|
70966
72166
|
}
|
|
70967
|
-
var followingCommand =
|
|
72167
|
+
var followingCommand = defineCommand248({
|
|
70968
72168
|
meta: {
|
|
70969
72169
|
name: "following",
|
|
70970
72170
|
description: "List brands you follow, with status (ready / adding\u2026) and cached counts. A brand's counts are only final once it is ready. Example: baker winning-ads following --output md"
|
|
@@ -71000,7 +72200,7 @@ var followingCommand = defineCommand244({
|
|
|
71000
72200
|
});
|
|
71001
72201
|
|
|
71002
72202
|
// src/commands/winning-ads/patterns.ts
|
|
71003
|
-
import { defineCommand as
|
|
72203
|
+
import { defineCommand as defineCommand249 } from "citty";
|
|
71004
72204
|
registerSchema({
|
|
71005
72205
|
command: "winning-ads.patterns",
|
|
71006
72206
|
description: "Mine what separates two cohorts of ads: pass a comma-list of winning ad ids (--winners) and a comma-list of weaker ad ids (--duds). Returns the discriminating DNA fields.",
|
|
@@ -71039,7 +72239,7 @@ function discriminatorRow(record) {
|
|
|
71039
72239
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
71040
72240
|
};
|
|
71041
72241
|
}
|
|
71042
|
-
var patternsCommand =
|
|
72242
|
+
var patternsCommand = defineCommand249({
|
|
71043
72243
|
meta: {
|
|
71044
72244
|
name: "patterns",
|
|
71045
72245
|
description: "Discover what separates winning ads from weak ones. Example: baker winning-ads patterns --winners a_1,a_2,a_3 --duds a_9,a_8 --output md"
|
|
@@ -71095,7 +72295,7 @@ var patternsCommand = defineCommand245({
|
|
|
71095
72295
|
});
|
|
71096
72296
|
|
|
71097
72297
|
// src/commands/winning-ads/search.ts
|
|
71098
|
-
import { defineCommand as
|
|
72298
|
+
import { defineCommand as defineCommand250 } from "citty";
|
|
71099
72299
|
registerSchema({
|
|
71100
72300
|
command: "winning-ads.search",
|
|
71101
72301
|
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.",
|
|
@@ -71168,15 +72368,15 @@ function setNumber(body, key, value) {
|
|
|
71168
72368
|
body[key] = Number(value);
|
|
71169
72369
|
}
|
|
71170
72370
|
}
|
|
71171
|
-
function setList(
|
|
71172
|
-
const
|
|
71173
|
-
if (
|
|
71174
|
-
|
|
72371
|
+
function setList(target4, key, value) {
|
|
72372
|
+
const list3 = splitList3(value);
|
|
72373
|
+
if (list3.length) {
|
|
72374
|
+
target4[key] = list3;
|
|
71175
72375
|
}
|
|
71176
72376
|
}
|
|
71177
|
-
function setString(
|
|
72377
|
+
function setString(target4, key, value) {
|
|
71178
72378
|
if (value) {
|
|
71179
|
-
|
|
72379
|
+
target4[key] = value;
|
|
71180
72380
|
}
|
|
71181
72381
|
}
|
|
71182
72382
|
function buildSearchBody2(args5) {
|
|
@@ -71233,7 +72433,7 @@ function reportSearchError(err) {
|
|
|
71233
72433
|
}
|
|
71234
72434
|
reportError2(err);
|
|
71235
72435
|
}
|
|
71236
|
-
var searchCommand5 =
|
|
72436
|
+
var searchCommand5 = defineCommand250({
|
|
71237
72437
|
meta: {
|
|
71238
72438
|
name: "search",
|
|
71239
72439
|
description: "Search winning reference ads. Example: baker winning-ads search 'B2B SaaS before/after AI automation' --platform meta --format static --winner-category winner --exclude-advertiser adv_123 --output md"
|
|
@@ -71353,7 +72553,7 @@ var searchCommand5 = defineCommand246({
|
|
|
71353
72553
|
});
|
|
71354
72554
|
|
|
71355
72555
|
// src/commands/winning-ads/seeds.ts
|
|
71356
|
-
import { defineCommand as
|
|
72556
|
+
import { defineCommand as defineCommand251 } from "citty";
|
|
71357
72557
|
function leanRow(r) {
|
|
71358
72558
|
return {
|
|
71359
72559
|
key: r.key,
|
|
@@ -71381,7 +72581,7 @@ function makeSeedCommand(opts) {
|
|
|
71381
72581
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
71382
72582
|
}
|
|
71383
72583
|
});
|
|
71384
|
-
return
|
|
72584
|
+
return defineCommand251({
|
|
71385
72585
|
meta: { name: opts.name, description: opts.description },
|
|
71386
72586
|
args: {
|
|
71387
72587
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -71430,7 +72630,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
71430
72630
|
});
|
|
71431
72631
|
|
|
71432
72632
|
// src/commands/winning-ads/unfollow.ts
|
|
71433
|
-
import { defineCommand as
|
|
72633
|
+
import { defineCommand as defineCommand252 } from "citty";
|
|
71434
72634
|
registerSchema({
|
|
71435
72635
|
command: "winning-ads.unfollow",
|
|
71436
72636
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -71438,7 +72638,7 @@ registerSchema({
|
|
|
71438
72638
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
71439
72639
|
}
|
|
71440
72640
|
});
|
|
71441
|
-
var unfollowCommand =
|
|
72641
|
+
var unfollowCommand = defineCommand252({
|
|
71442
72642
|
meta: {
|
|
71443
72643
|
name: "unfollow",
|
|
71444
72644
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -71459,7 +72659,7 @@ var unfollowCommand = defineCommand248({
|
|
|
71459
72659
|
});
|
|
71460
72660
|
|
|
71461
72661
|
// src/commands/winning-ads/winners.ts
|
|
71462
|
-
import { defineCommand as
|
|
72662
|
+
import { defineCommand as defineCommand253 } from "citty";
|
|
71463
72663
|
registerSchema({
|
|
71464
72664
|
command: "winning-ads.winners",
|
|
71465
72665
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -71469,7 +72669,7 @@ registerSchema({
|
|
|
71469
72669
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
71470
72670
|
}
|
|
71471
72671
|
});
|
|
71472
|
-
var winnersCommand =
|
|
72672
|
+
var winnersCommand = defineCommand253({
|
|
71473
72673
|
meta: {
|
|
71474
72674
|
name: "winners",
|
|
71475
72675
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -71519,7 +72719,7 @@ var winnersCommand = defineCommand249({
|
|
|
71519
72719
|
});
|
|
71520
72720
|
|
|
71521
72721
|
// src/commands/winning-ads/index.ts
|
|
71522
|
-
var winningAdsCommand =
|
|
72722
|
+
var winningAdsCommand = defineCommand254({
|
|
71523
72723
|
meta: {
|
|
71524
72724
|
name: "winning-ads",
|
|
71525
72725
|
description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
|
|
@@ -71730,12 +72930,12 @@ function suggestionText(suggestion) {
|
|
|
71730
72930
|
}
|
|
71731
72931
|
var OUTPUT_EXPLANATION = "This command has no --output option: `--output json` is accepted by every command that prints the JSON envelope, and md or files only where `baker schema` lists `output`. Drop the option and read the default output. ";
|
|
71732
72932
|
function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
71733
|
-
const
|
|
72933
|
+
const list3 = unknown.join(", ");
|
|
71734
72934
|
return {
|
|
71735
72935
|
ok: false,
|
|
71736
72936
|
error: {
|
|
71737
72937
|
code: "UNKNOWN_ARGUMENT",
|
|
71738
|
-
message: `${
|
|
72938
|
+
message: `${list3} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
71739
72939
|
fix: {
|
|
71740
72940
|
action: hasSchema ? "check_schema" : "check_help",
|
|
71741
72941
|
explanation: (unknown.some((flag3) => flag3 === "--output" || flag3.startsWith("--output=")) ? OUTPUT_EXPLANATION : "") + suggestionText(suggestion) + `Run \`${hasSchema ? `baker schema ${commandPath}` : `baker ${commandPath} --help`}\` to see every option this command takes. Do not re-run the same call: until this version an unrecognised option was accepted and ignored, so a command that looked like it had filtered or narrowed the result was in fact answering the unfiltered question.`
|
|
@@ -71846,7 +73046,7 @@ function getCliVersion() {
|
|
|
71846
73046
|
}
|
|
71847
73047
|
|
|
71848
73048
|
// src/cli.ts
|
|
71849
|
-
var main =
|
|
73049
|
+
var main = defineCommand255({
|
|
71850
73050
|
meta: {
|
|
71851
73051
|
name: "baker",
|
|
71852
73052
|
version: getCliVersion(),
|