@koda-sl/baker-cli 0.383.0-dev.3b7d77b41 → 0.383.0-dev.9b0f8605e
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 +47 -3
- package/dist/cli.js +1984 -494
- package/dist/cli.js.map +1 -1
- package/package.json +2 -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 defineCommand256, 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),
|
|
@@ -5087,6 +5111,20 @@ var FLOW_SIDE_EFFECT_CATALOG = [
|
|
|
5087
5111
|
reference: SIDE_EFFECT_REF("httpWebhook")
|
|
5088
5112
|
},
|
|
5089
5113
|
crmSideEffect("googleSpreadsheet", "Appends a row to a Google Sheet.", "columnMapping", MAP_FIRST),
|
|
5114
|
+
{
|
|
5115
|
+
kind: "side-effect",
|
|
5116
|
+
type: "shopifyCustomer",
|
|
5117
|
+
summary: "Adds a sign-up to the connected Shopify store with the consent they ticked.",
|
|
5118
|
+
skeleton: {
|
|
5119
|
+
...SIDE_EFFECT_ENVELOPE,
|
|
5120
|
+
type: "shopifyCustomer",
|
|
5121
|
+
customer: { email: null, phone: null, acceptsEmailMarketing: null, acceptsSmsMarketing: null },
|
|
5122
|
+
offer: null
|
|
5123
|
+
},
|
|
5124
|
+
owners: { customer: "agent", offer: "agent" },
|
|
5125
|
+
gotcha: "Map email to an email field with baker flows map. Email and SMS consent each need their own optional, visible, initially unticked checkbox; SMS also needs phone. No connection secret is needed. An optional offer names a published sign-up offer; read baker shopify signup-offers. Show its code with ShopifySignupCode.",
|
|
5126
|
+
reference: SIDE_EFFECT_REF("shopifyCustomer")
|
|
5127
|
+
},
|
|
5090
5128
|
crmSideEffect("hubspotForm", "Submits to a HubSpot form endpoint.", "fieldMapping", MAP_FIRST),
|
|
5091
5129
|
crmSideEffect("pipedrive", "Creates or updates a Pipedrive record.", "fieldMapping", MAP_FIRST),
|
|
5092
5130
|
crmSideEffect("goHighlevelContact", "Creates or updates a GoHighLevel contact.", "fieldMapping", MAP_FIRST),
|
|
@@ -6970,7 +7008,6 @@ var STORE_EVENTS = {
|
|
|
6970
7008
|
product_out_of_stock: {
|
|
6971
7009
|
label: "A product runs out of stock",
|
|
6972
7010
|
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
7011
|
payload: [
|
|
6975
7012
|
"title",
|
|
6976
7013
|
"handle",
|
|
@@ -6981,13 +7018,11 @@ var STORE_EVENTS = {
|
|
|
6981
7018
|
"promoted_by",
|
|
6982
7019
|
"promotions_checked",
|
|
6983
7020
|
...PRODUCT_FIELDS.slice(2)
|
|
6984
|
-
]
|
|
6985
|
-
namesProduct: true
|
|
7021
|
+
]
|
|
6986
7022
|
},
|
|
6987
7023
|
product_back_in_stock: {
|
|
6988
7024
|
label: "A product is back in stock",
|
|
6989
7025
|
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
7026
|
payload: [
|
|
6992
7027
|
"title",
|
|
6993
7028
|
"handle",
|
|
@@ -6998,20 +7033,16 @@ var STORE_EVENTS = {
|
|
|
6998
7033
|
"reason",
|
|
6999
7034
|
"promoted_by",
|
|
7000
7035
|
...PRODUCT_FIELDS.slice(2)
|
|
7001
|
-
]
|
|
7002
|
-
namesProduct: true
|
|
7036
|
+
]
|
|
7003
7037
|
},
|
|
7004
7038
|
product_created: {
|
|
7005
7039
|
label: "A new product is added",
|
|
7006
7040
|
sentence: "When a new product is added to your Shopify store",
|
|
7007
|
-
|
|
7008
|
-
payload: [...PRODUCT_FIELDS],
|
|
7009
|
-
namesProduct: true
|
|
7041
|
+
payload: [...PRODUCT_FIELDS]
|
|
7010
7042
|
},
|
|
7011
7043
|
product_updated: {
|
|
7012
7044
|
label: "A product is changed",
|
|
7013
7045
|
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
7046
|
payload: [
|
|
7016
7047
|
"title",
|
|
7017
7048
|
"handle",
|
|
@@ -7022,41 +7053,33 @@ var STORE_EVENTS = {
|
|
|
7022
7053
|
"before_published",
|
|
7023
7054
|
"price_changes",
|
|
7024
7055
|
...PRODUCT_FIELDS.slice(2)
|
|
7025
|
-
]
|
|
7026
|
-
namesProduct: true
|
|
7056
|
+
]
|
|
7027
7057
|
},
|
|
7028
7058
|
collection_updated: {
|
|
7029
7059
|
label: "A collection changes",
|
|
7030
7060
|
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
|
|
7061
|
+
payload: ["title", "collection", "changed", "product_count", "before_product_count", "published", "store"]
|
|
7034
7062
|
},
|
|
7035
7063
|
purchase: {
|
|
7036
7064
|
label: "An order is paid",
|
|
7037
7065
|
sentence: "When an order is paid",
|
|
7038
|
-
description: "The store's sale; value is the order's total in the store's currency.",
|
|
7039
7066
|
payload: ["order_name", "ordered_at", "shopify_source", "visitor_from", "campaign_from", "store"],
|
|
7040
|
-
|
|
7067
|
+
alsoTheSite: true
|
|
7041
7068
|
},
|
|
7042
7069
|
refund: {
|
|
7043
7070
|
label: "Money is refunded on an order",
|
|
7044
7071
|
sentence: "When money is refunded on an order",
|
|
7045
|
-
description: "Money given back on an order; value is the amount refunded.",
|
|
7046
7072
|
payload: ["order_name", "store"],
|
|
7047
|
-
|
|
7073
|
+
alsoTheSite: true
|
|
7048
7074
|
},
|
|
7049
7075
|
customer_created: {
|
|
7050
7076
|
label: "A new customer signs up",
|
|
7051
7077
|
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
|
|
7078
|
+
payload: ["customer", "country", "accepts_email", "orders", "tags", "account_state", "store"]
|
|
7055
7079
|
},
|
|
7056
7080
|
checkout_abandoned: {
|
|
7057
7081
|
label: "A checkout is abandoned",
|
|
7058
7082
|
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
7083
|
payload: [
|
|
7061
7084
|
"total",
|
|
7062
7085
|
"currency",
|
|
@@ -7069,13 +7092,11 @@ var STORE_EVENTS = {
|
|
|
7069
7092
|
"started_at",
|
|
7070
7093
|
"last_activity_at",
|
|
7071
7094
|
"store"
|
|
7072
|
-
]
|
|
7073
|
-
namesProduct: false
|
|
7095
|
+
]
|
|
7074
7096
|
},
|
|
7075
7097
|
sales_drop: {
|
|
7076
7098
|
label: "Sales drop",
|
|
7077
7099
|
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
7100
|
payload: [
|
|
7080
7101
|
"window_hours",
|
|
7081
7102
|
"window_start",
|
|
@@ -7088,11 +7109,73 @@ var STORE_EVENTS = {
|
|
|
7088
7109
|
"drop_percent",
|
|
7089
7110
|
"baseline_days",
|
|
7090
7111
|
"store"
|
|
7091
|
-
]
|
|
7092
|
-
namesProduct: false
|
|
7112
|
+
]
|
|
7093
7113
|
}
|
|
7094
7114
|
};
|
|
7095
7115
|
var STORE_EVENT_NAMES = Object.keys(STORE_EVENTS);
|
|
7116
|
+
var STORE_FIELD_LABELS = {
|
|
7117
|
+
baker_source: "Comes from",
|
|
7118
|
+
store: "Store",
|
|
7119
|
+
title: "Product",
|
|
7120
|
+
handle: "Product address",
|
|
7121
|
+
status: "Status",
|
|
7122
|
+
published: "On the store",
|
|
7123
|
+
price: "Price",
|
|
7124
|
+
price_max: "Highest price",
|
|
7125
|
+
currency: "Currency",
|
|
7126
|
+
collections: "Collections",
|
|
7127
|
+
tags: "Tags",
|
|
7128
|
+
product_type: "Product type",
|
|
7129
|
+
vendor: "Brand",
|
|
7130
|
+
product_url: "Product page",
|
|
7131
|
+
whole_product: "Whole product out of stock",
|
|
7132
|
+
options_out: "Options out of stock",
|
|
7133
|
+
options_out_count: "How many options are out",
|
|
7134
|
+
options_count: "How many options it has",
|
|
7135
|
+
promoted_by: "Ads found",
|
|
7136
|
+
promotions_checked: "Where Baker looked for ads",
|
|
7137
|
+
whole_product_was_out: "Whole product was out of stock",
|
|
7138
|
+
options_back: "Options back in stock",
|
|
7139
|
+
still_out_count: "Options still out of stock",
|
|
7140
|
+
stock_holds: "Ads Baker paused",
|
|
7141
|
+
reason: "Why",
|
|
7142
|
+
changed: "What changed",
|
|
7143
|
+
before_title: "Name before",
|
|
7144
|
+
before_price: "Price before",
|
|
7145
|
+
before_status: "Status before",
|
|
7146
|
+
before_published: "On the store before",
|
|
7147
|
+
price_changes: "Price changes",
|
|
7148
|
+
collection: "Collection",
|
|
7149
|
+
product_count: "Products",
|
|
7150
|
+
before_product_count: "Products before",
|
|
7151
|
+
order_name: "Order",
|
|
7152
|
+
ordered_at: "Ordered at",
|
|
7153
|
+
shopify_source: "Sold through",
|
|
7154
|
+
visitor_from: "Shopper came from",
|
|
7155
|
+
campaign_from: "Campaign",
|
|
7156
|
+
customer: "Customer",
|
|
7157
|
+
country: "Country",
|
|
7158
|
+
accepts_email: "Accepts email",
|
|
7159
|
+
orders: "Orders",
|
|
7160
|
+
account_state: "Account",
|
|
7161
|
+
total: "Total",
|
|
7162
|
+
items_count: "Items",
|
|
7163
|
+
products: "Products",
|
|
7164
|
+
product_handles: "Product addresses",
|
|
7165
|
+
known_customer: "Known customer",
|
|
7166
|
+
discount_codes_count: "Discount codes",
|
|
7167
|
+
started_at: "Started at",
|
|
7168
|
+
last_activity_at: "Last active at",
|
|
7169
|
+
window_hours: "Hours looked at",
|
|
7170
|
+
window_start: "From",
|
|
7171
|
+
window_end: "To",
|
|
7172
|
+
expected_orders: "Usual orders",
|
|
7173
|
+
revenue: "Sales",
|
|
7174
|
+
expected_revenue: "Usual sales",
|
|
7175
|
+
drop_percent: "Drop (%)",
|
|
7176
|
+
baseline_days: "Days compared"
|
|
7177
|
+
};
|
|
7178
|
+
var FIELD_LABELS = new Map(Object.entries(STORE_FIELD_LABELS));
|
|
7096
7179
|
|
|
7097
7180
|
// ../api/src/scheduledAgentRules.ts
|
|
7098
7181
|
var CONDITION_OPERATORS = {
|
|
@@ -8435,8 +8518,8 @@ var videosDeleteResponseSchema = z29.object({ ok: z29.literal(true) });
|
|
|
8435
8518
|
|
|
8436
8519
|
// src/commands/actions/tagError.ts
|
|
8437
8520
|
var UNKNOWN_TAG_RE = /Unknown action tag\(s\): ([^.]+)\. Valid tags: ([^.]+)\./;
|
|
8438
|
-
function splitSlugs(
|
|
8439
|
-
return
|
|
8521
|
+
function splitSlugs(list3) {
|
|
8522
|
+
return list3.split(",").map((slug) => slug.trim()).filter((slug) => slug.length > 0);
|
|
8440
8523
|
}
|
|
8441
8524
|
function actionTagFix(message) {
|
|
8442
8525
|
const match = UNKNOWN_TAG_RE.exec(message);
|
|
@@ -8535,9 +8618,9 @@ function parsePriority(value, { allowClear }) {
|
|
|
8535
8618
|
`Unknown --priority "${value}". Expected one of: ${ACTION_PRIORITIES.join(", ")}${allowClear ? ", or 'none' to clear" : ""}.`
|
|
8536
8619
|
);
|
|
8537
8620
|
}
|
|
8538
|
-
function looksScheduled(name,
|
|
8621
|
+
function looksScheduled(name, description2) {
|
|
8539
8622
|
const haystack = fold(`${name}
|
|
8540
|
-
${
|
|
8623
|
+
${description2}`);
|
|
8541
8624
|
return SCHEDULE_SIGNALS.some((re2) => re2.test(haystack));
|
|
8542
8625
|
}
|
|
8543
8626
|
var CAMPAIGN_ENTITY = String.raw`(?:campaigns?|campanas?|ad\s*sets?|adsets?|ad\s*groups?|adgroups?|ads?|anuncios?|conjuntos?\s+de\s+anuncios|grupos?\s+de\s+anuncios)`;
|
|
@@ -8695,10 +8778,10 @@ var SURFACE_RULES = [
|
|
|
8695
8778
|
var FAN_OUT_NUDGE_THRESHOLD = 2;
|
|
8696
8779
|
var FAN_OUT_THRESHOLD = 3;
|
|
8697
8780
|
var SCHEDULED_HINT = 'This reads as recurring/scheduled work. If it should run on a cadence or a future date, create a Scheduled agent instead \u2014 baker scheduled-agents create --cron "0 9 * * MON" (or --run-at, or --trigger for a reaction rather than a clock; guide: `__tooling__/docs/tools/baker/scheduled-agents.md`). Do not capture "set up a schedule" as a Work Action.';
|
|
8698
|
-
function looksExecutable(name,
|
|
8781
|
+
function looksExecutable(name, description2) {
|
|
8699
8782
|
const foldedName = fold(name);
|
|
8700
8783
|
const full = `${foldedName}
|
|
8701
|
-
${fold(
|
|
8784
|
+
${fold(description2)}`;
|
|
8702
8785
|
for (const rule of SURFACE_RULES) {
|
|
8703
8786
|
const haystack = rule.nameOnly ? foldedName : full;
|
|
8704
8787
|
if (rule.except?.some((re2) => re2.test(full))) {
|
|
@@ -8718,7 +8801,7 @@ ${fold(description)}`;
|
|
|
8718
8801
|
}
|
|
8719
8802
|
function buildCreateHints({
|
|
8720
8803
|
name,
|
|
8721
|
-
description,
|
|
8804
|
+
description: description2,
|
|
8722
8805
|
tempId,
|
|
8723
8806
|
tags,
|
|
8724
8807
|
prioritySet,
|
|
@@ -8726,13 +8809,13 @@ function buildCreateHints({
|
|
|
8726
8809
|
}) {
|
|
8727
8810
|
const hints2 = [];
|
|
8728
8811
|
const expanded = shellExpandedIn(`${name}
|
|
8729
|
-
${
|
|
8812
|
+
${description2}`);
|
|
8730
8813
|
if (expanded) {
|
|
8731
8814
|
hints2.push(
|
|
8732
8815
|
`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.`
|
|
8733
8816
|
);
|
|
8734
8817
|
}
|
|
8735
|
-
const advisory = advisoryHint(name,
|
|
8818
|
+
const advisory = advisoryHint(name, description2);
|
|
8736
8819
|
if (advisory) {
|
|
8737
8820
|
hints2.push(
|
|
8738
8821
|
`${advisory.hint} If nothing actually blocks it: baker actions draft remove ${tempId}, then do the work.`
|
|
@@ -8748,7 +8831,7 @@ ${description}`);
|
|
|
8748
8831
|
);
|
|
8749
8832
|
}
|
|
8750
8833
|
hints2.push(`Link dependencies: baker actions link --blocker <id> --blocked ${tempId}`);
|
|
8751
|
-
if (!
|
|
8834
|
+
if (!description2) {
|
|
8752
8835
|
hints2.push("Add description: baker actions update <tempId> --description '...' (what/why/where/done-when)");
|
|
8753
8836
|
}
|
|
8754
8837
|
if (!tags || tags.length === 0) {
|
|
@@ -8766,11 +8849,11 @@ ${description}`);
|
|
|
8766
8849
|
function shellExpandedIn(text2) {
|
|
8767
8850
|
return /(?:^|[\s(])((?:\/usr)?\/bin\/(?:ba|z|da|k)?sh|-?(?:ba|z|da|k)sh)\b/.exec(text2)?.[1] ?? null;
|
|
8768
8851
|
}
|
|
8769
|
-
function advisoryHint(name,
|
|
8770
|
-
if (looksScheduled(name,
|
|
8852
|
+
function advisoryHint(name, description2) {
|
|
8853
|
+
if (looksScheduled(name, description2)) {
|
|
8771
8854
|
return { kind: "scheduled", hint: SCHEDULED_HINT };
|
|
8772
8855
|
}
|
|
8773
|
-
const executable = looksExecutable(name,
|
|
8856
|
+
const executable = looksExecutable(name, description2);
|
|
8774
8857
|
return executable ? { kind: "executable", ...executable } : null;
|
|
8775
8858
|
}
|
|
8776
8859
|
var ACTIONS_LIST_DEFAULT_LIMIT = 500;
|
|
@@ -8856,9 +8939,9 @@ function parseSkillFrontmatter(md) {
|
|
|
8856
8939
|
const lines = extractFrontmatterLines(md);
|
|
8857
8940
|
if (!lines) return null;
|
|
8858
8941
|
const name = readField(lines, "name");
|
|
8859
|
-
const
|
|
8860
|
-
if (!name || !
|
|
8861
|
-
const trimmed =
|
|
8942
|
+
const description2 = readField(lines, "description");
|
|
8943
|
+
if (!name || !description2) return null;
|
|
8944
|
+
const trimmed = description2.length > DESCRIPTION_MAX ? `${description2.slice(0, DESCRIPTION_MAX)}\u2026` : description2;
|
|
8862
8945
|
return { name, description: trimmed };
|
|
8863
8946
|
}
|
|
8864
8947
|
function findSkillsDir(startDir) {
|
|
@@ -11601,8 +11684,8 @@ function capabilityFix(surface) {
|
|
|
11601
11684
|
// src/commands/ads/boolean-word-positional.ts
|
|
11602
11685
|
var BOOLEAN_WORD = /^(true|false)$/i;
|
|
11603
11686
|
function booleanWordPositionalError(args5, entity) {
|
|
11604
|
-
const
|
|
11605
|
-
const word =
|
|
11687
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
11688
|
+
const word = positionals2.find((value2) => typeof value2 === "string" && BOOLEAN_WORD.test(value2));
|
|
11606
11689
|
if (word === void 0) {
|
|
11607
11690
|
return void 0;
|
|
11608
11691
|
}
|
|
@@ -11936,7 +12019,7 @@ function words(headline) {
|
|
|
11936
12019
|
return headline.toLowerCase().replace(/[^\p{L}\p{N}\s]/gu, " ").split(/\s+/).filter(Boolean);
|
|
11937
12020
|
}
|
|
11938
12021
|
function canonical(word) {
|
|
11939
|
-
for (const [i,
|
|
12022
|
+
for (const [i, group2] of CYCLED_VERBS.entries()) if (group2.includes(word)) return `group:${i}`;
|
|
11940
12023
|
return word;
|
|
11941
12024
|
}
|
|
11942
12025
|
function overlap(a, b) {
|
|
@@ -12211,11 +12294,11 @@ function requireTarget(args5, entity) {
|
|
|
12211
12294
|
failWriteValidation(booleanWord);
|
|
12212
12295
|
}
|
|
12213
12296
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
12214
|
-
const
|
|
12215
|
-
if (typeof
|
|
12297
|
+
const target4 = args5.id ?? args5.target ?? args5.ref ?? positional;
|
|
12298
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
12216
12299
|
failWriteValidation(`pass the ${entity} resource name or id as the positional argument`);
|
|
12217
12300
|
}
|
|
12218
|
-
return
|
|
12301
|
+
return target4;
|
|
12219
12302
|
}
|
|
12220
12303
|
function requireStringFlag(value, flag3) {
|
|
12221
12304
|
if (typeof value !== "string" || value.length === 0) {
|
|
@@ -12423,11 +12506,11 @@ async function stageGoogleOps(rawOps, hints2) {
|
|
|
12423
12506
|
handleGoogleError(err);
|
|
12424
12507
|
}
|
|
12425
12508
|
}
|
|
12426
|
-
async function stageUpdate(kind, customerId,
|
|
12427
|
-
await stageGoogleOp({ kind, customerId, target:
|
|
12509
|
+
async function stageUpdate(kind, customerId, target4, payload, hints2) {
|
|
12510
|
+
await stageGoogleOp({ kind, customerId, target: target4, payload }, hints2);
|
|
12428
12511
|
}
|
|
12429
|
-
async function stageTarget(kind, customerId,
|
|
12430
|
-
await stageGoogleOp({ kind, customerId, target:
|
|
12512
|
+
async function stageTarget(kind, customerId, target4, hints2) {
|
|
12513
|
+
await stageGoogleOp({ kind, customerId, target: target4 }, hints2);
|
|
12431
12514
|
}
|
|
12432
12515
|
async function draftAction(path49, body, chat) {
|
|
12433
12516
|
try {
|
|
@@ -12606,9 +12689,9 @@ var DATAFORSEO_LANGUAGES = [
|
|
|
12606
12689
|
{ code: "da", name: "Danish" },
|
|
12607
12690
|
{ code: "fi", name: "Finnish" }
|
|
12608
12691
|
];
|
|
12609
|
-
function toRecord(
|
|
12692
|
+
function toRecord(list3) {
|
|
12610
12693
|
const map = {};
|
|
12611
|
-
for (const item of
|
|
12694
|
+
for (const item of list3) {
|
|
12612
12695
|
const key = item.id ?? item.code;
|
|
12613
12696
|
if (key) map[key] = item.name;
|
|
12614
12697
|
}
|
|
@@ -13984,9 +14067,9 @@ function servingScopeWarnings(args5, finalQuery) {
|
|
|
13984
14067
|
}
|
|
13985
14068
|
function parseSelectedFields(gaql) {
|
|
13986
14069
|
const match = gaql.match(/\bSELECT\b([\s\S]*?)\bFROM\b/i);
|
|
13987
|
-
const
|
|
13988
|
-
if (!
|
|
13989
|
-
return
|
|
14070
|
+
const list3 = match?.[1];
|
|
14071
|
+
if (!list3) return [];
|
|
14072
|
+
return list3.split(",").map((field) => field.trim()).filter((field) => /^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z0-9_]+)*$/.test(field));
|
|
13990
14073
|
}
|
|
13991
14074
|
function foldObservedFields(rows, observed) {
|
|
13992
14075
|
for (const row of rows) {
|
|
@@ -14983,6 +15066,7 @@ var DESTINATION_NAMES = {
|
|
|
14983
15066
|
googleSpreadsheet: "Google Sheets",
|
|
14984
15067
|
hubspotForm: "HubSpot Form",
|
|
14985
15068
|
goHighlevelContact: "GoHighLevel",
|
|
15069
|
+
shopifyCustomer: "Shopify",
|
|
14986
15070
|
crmble: "Crmble"
|
|
14987
15071
|
};
|
|
14988
15072
|
function destinationKey(type) {
|
|
@@ -18441,13 +18525,13 @@ var budgetsCommand = defineCommand31({
|
|
|
18441
18525
|
},
|
|
18442
18526
|
run: async ({ args: args5 }) => {
|
|
18443
18527
|
const customerId = requireCustomerId(args5);
|
|
18444
|
-
const
|
|
18528
|
+
const target4 = requireTarget(args5, "budget");
|
|
18445
18529
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
18446
18530
|
name: args5.name,
|
|
18447
18531
|
amountMicros: microsFlag(args5.amount, "--amount"),
|
|
18448
18532
|
deliveryMethod: args5.delivery
|
|
18449
18533
|
});
|
|
18450
|
-
await stageUpdate("google.budget.update", customerId,
|
|
18534
|
+
await stageUpdate("google.budget.update", customerId, target4, payload, BUDGET_DEMAND_HINTS);
|
|
18451
18535
|
}
|
|
18452
18536
|
})
|
|
18453
18537
|
}
|
|
@@ -18763,7 +18847,7 @@ var campaignsCommand = defineCommand31({
|
|
|
18763
18847
|
if (level !== "campaign") {
|
|
18764
18848
|
failWriteValidation("--level must be campaign or account");
|
|
18765
18849
|
}
|
|
18766
|
-
const
|
|
18850
|
+
const target4 = requireTarget(args5, "campaign");
|
|
18767
18851
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
18768
18852
|
name: args5.name,
|
|
18769
18853
|
budget: args5["budget-ref"],
|
|
@@ -18776,7 +18860,7 @@ var campaignsCommand = defineCommand31({
|
|
|
18776
18860
|
euPoliticalAds: args5["eu-political-ads"],
|
|
18777
18861
|
status: args5.status
|
|
18778
18862
|
});
|
|
18779
|
-
await stageUpdate("google.campaign.update", customerId,
|
|
18863
|
+
await stageUpdate("google.campaign.update", customerId, target4, payload);
|
|
18780
18864
|
}
|
|
18781
18865
|
}),
|
|
18782
18866
|
pause: statusCommand2("google.campaign.pause", "campaign"),
|
|
@@ -18846,13 +18930,13 @@ var adGroupsCommand = defineCommand31({
|
|
|
18846
18930
|
},
|
|
18847
18931
|
run: async ({ args: args5 }) => {
|
|
18848
18932
|
const customerId = requireCustomerId(args5);
|
|
18849
|
-
const
|
|
18933
|
+
const target4 = requireTarget(args5, "ad group");
|
|
18850
18934
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
18851
18935
|
name: args5.name,
|
|
18852
18936
|
cpcBidMicros: microsFlag(args5["cpc-bid"], "--cpc-bid"),
|
|
18853
18937
|
status: args5.status
|
|
18854
18938
|
});
|
|
18855
|
-
await stageUpdate("google.adGroup.update", customerId,
|
|
18939
|
+
await stageUpdate("google.adGroup.update", customerId, target4, payload);
|
|
18856
18940
|
}
|
|
18857
18941
|
}),
|
|
18858
18942
|
pause: statusCommand2("google.adGroup.pause", "ad group"),
|
|
@@ -18880,11 +18964,11 @@ function keywordFinalUrlHints(finalUrl, count2) {
|
|
|
18880
18964
|
}
|
|
18881
18965
|
function keywordUpdateFinalUrls(args5) {
|
|
18882
18966
|
const finalUrl = args5["final-url"];
|
|
18883
|
-
const
|
|
18967
|
+
const clear2 = args5["clear-final-url"] === true;
|
|
18884
18968
|
if (typeof finalUrl !== "string" || finalUrl.length === 0) {
|
|
18885
|
-
return
|
|
18969
|
+
return clear2 ? [] : void 0;
|
|
18886
18970
|
}
|
|
18887
|
-
if (
|
|
18971
|
+
if (clear2) {
|
|
18888
18972
|
failWriteValidation(
|
|
18889
18973
|
"--clear-final-url sends the keyword back to the ad's landing page \u2014 pass it OR --final-url, not both"
|
|
18890
18974
|
);
|
|
@@ -19500,13 +19584,13 @@ var assetGroupsCommand = defineCommand31({
|
|
|
19500
19584
|
},
|
|
19501
19585
|
run: async ({ args: args5 }) => {
|
|
19502
19586
|
const customerId = requireCustomerId(args5);
|
|
19503
|
-
const
|
|
19587
|
+
const target4 = requireTarget(args5, "asset group");
|
|
19504
19588
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
19505
19589
|
name: args5.name,
|
|
19506
19590
|
finalUrls: listFlag(args5["final-urls"]),
|
|
19507
19591
|
status: args5.status
|
|
19508
19592
|
});
|
|
19509
|
-
await stageUpdate("google.assetGroup.update", customerId,
|
|
19593
|
+
await stageUpdate("google.assetGroup.update", customerId, target4, payload);
|
|
19510
19594
|
}
|
|
19511
19595
|
}),
|
|
19512
19596
|
attach: defineCommand31({
|
|
@@ -19544,9 +19628,9 @@ var assetGroupsCommand = defineCommand31({
|
|
|
19544
19628
|
])
|
|
19545
19629
|
}
|
|
19546
19630
|
});
|
|
19547
|
-
function fileCreateCommand(name, kind,
|
|
19631
|
+
function fileCreateCommand(name, kind, description2, hints2) {
|
|
19548
19632
|
return defineCommand31({
|
|
19549
|
-
meta: { name, description },
|
|
19633
|
+
meta: { name, description: description2 },
|
|
19550
19634
|
args: { ...customerIdArg, ...fileArg },
|
|
19551
19635
|
run: async ({ args: args5 }) => {
|
|
19552
19636
|
const customerId = requireCustomerId(args5);
|
|
@@ -19588,7 +19672,7 @@ var assetsUpdateCommand = defineCommand31({
|
|
|
19588
19672
|
},
|
|
19589
19673
|
run: async ({ args: args5 }) => {
|
|
19590
19674
|
const customerId = requireCustomerId(args5);
|
|
19591
|
-
const
|
|
19675
|
+
const target4 = requireTarget(args5, "asset");
|
|
19592
19676
|
const payload = mergePayload(loadJsonFileArg(args5.file), {
|
|
19593
19677
|
name: args5.name,
|
|
19594
19678
|
linkText: args5["link-text"],
|
|
@@ -19601,7 +19685,7 @@ var assetsUpdateCommand = defineCommand31({
|
|
|
19601
19685
|
callToAction: args5.cta,
|
|
19602
19686
|
text: args5.text
|
|
19603
19687
|
});
|
|
19604
|
-
await stageUpdate("google.asset.update", customerId,
|
|
19688
|
+
await stageUpdate("google.asset.update", customerId, target4, payload);
|
|
19605
19689
|
}
|
|
19606
19690
|
});
|
|
19607
19691
|
var assetsCommand = defineCommand31({
|
|
@@ -19914,8 +19998,8 @@ var campaignCriteriaCommand = defineCommand31({
|
|
|
19914
19998
|
},
|
|
19915
19999
|
run: async ({ args: args5 }) => {
|
|
19916
20000
|
const customerId = requireCustomerId(args5);
|
|
19917
|
-
const
|
|
19918
|
-
await stageUpdate("google.campaignCriterion.update", customerId,
|
|
20001
|
+
const target4 = requireTarget(args5, "campaign criterion");
|
|
20002
|
+
await stageUpdate("google.campaignCriterion.update", customerId, target4, {
|
|
19919
20003
|
bidModifier: bidModifierFlag(args5["bid-modifier"])
|
|
19920
20004
|
});
|
|
19921
20005
|
}
|
|
@@ -20345,7 +20429,7 @@ async function stageLinkedinOps(rawOps, hints2) {
|
|
|
20345
20429
|
async function stageStatusChange(input) {
|
|
20346
20430
|
const payload = input.kind === "creative.update" ? { intendedStatus: input.status } : { status: input.status };
|
|
20347
20431
|
await stageLinkedinOps(
|
|
20348
|
-
input.targets.map((
|
|
20432
|
+
input.targets.map((target4) => ({ kind: input.kind, accountId: input.accountId, target: target4, payload }))
|
|
20349
20433
|
);
|
|
20350
20434
|
}
|
|
20351
20435
|
function requireTarget2(args5, entity) {
|
|
@@ -20353,17 +20437,17 @@ function requireTarget2(args5, entity) {
|
|
|
20353
20437
|
if (inverted !== void 0) {
|
|
20354
20438
|
failWriteValidation2(inverted);
|
|
20355
20439
|
}
|
|
20356
|
-
const
|
|
20357
|
-
const
|
|
20358
|
-
if (typeof
|
|
20440
|
+
const positionals2 = readPositionals(args5);
|
|
20441
|
+
const target4 = args5.id ?? args5.target ?? args5.ref ?? positionals2[0];
|
|
20442
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
20359
20443
|
failWriteValidation2(`pass the ${entity} id or URN as the positional argument`);
|
|
20360
20444
|
}
|
|
20361
|
-
if (
|
|
20445
|
+
if (positionals2.length > 1 || splitIdList(target4).length > 1) {
|
|
20362
20446
|
failWriteValidation2(
|
|
20363
20447
|
`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.`
|
|
20364
20448
|
);
|
|
20365
20449
|
}
|
|
20366
|
-
return
|
|
20450
|
+
return target4;
|
|
20367
20451
|
}
|
|
20368
20452
|
function readPositionals(args5) {
|
|
20369
20453
|
if (!Array.isArray(args5._)) {
|
|
@@ -20381,11 +20465,11 @@ function idsFileEntries(path49) {
|
|
|
20381
20465
|
return readFileSync5(path49, "utf8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).flatMap(splitIdList);
|
|
20382
20466
|
}
|
|
20383
20467
|
function requireTargets(args5, entity) {
|
|
20384
|
-
const
|
|
20468
|
+
const positionals2 = readPositionals(args5);
|
|
20385
20469
|
const named = [args5.id, args5.target, args5.ref].filter(
|
|
20386
20470
|
(value) => typeof value === "string" && value.length > 0
|
|
20387
20471
|
);
|
|
20388
|
-
const fromArgs =
|
|
20472
|
+
const fromArgs = positionals2.length > 0 ? positionals2 : named;
|
|
20389
20473
|
const targets = [.../* @__PURE__ */ new Set([...fromArgs.flatMap(splitIdList), ...idsFileEntries(args5["ids-file"])])];
|
|
20390
20474
|
if (targets.length === 0) {
|
|
20391
20475
|
failWriteValidation2(
|
|
@@ -21329,9 +21413,9 @@ Example: baker ads linkedin campaigns create --name "ABM Tier-1" --group li_temp
|
|
|
21329
21413
|
await stageOp({ kind: "campaign.create", accountId, payload });
|
|
21330
21414
|
}
|
|
21331
21415
|
});
|
|
21332
|
-
function campaignUpdatePayloadFromFlags(args5,
|
|
21416
|
+
function campaignUpdatePayloadFromFlags(args5, target4, file) {
|
|
21333
21417
|
const flags = campaignPayloadFromFlags(args5);
|
|
21334
|
-
if (!
|
|
21418
|
+
if (!target4.startsWith(TEMP_REF_PREFIX)) {
|
|
21335
21419
|
flags.campaignGroup = void 0;
|
|
21336
21420
|
flags.type = void 0;
|
|
21337
21421
|
flags.locale = void 0;
|
|
@@ -21352,9 +21436,9 @@ Example: baker ads linkedin campaigns update 123456 --daily-budget 100 --currenc
|
|
|
21352
21436
|
},
|
|
21353
21437
|
run: async ({ args: args5 }) => {
|
|
21354
21438
|
const accountId = bareAccountId(args5);
|
|
21355
|
-
const
|
|
21356
|
-
const payload = campaignUpdatePayloadFromFlags(args5,
|
|
21357
|
-
await stageOp({ kind: "campaign.update", accountId, target:
|
|
21439
|
+
const target4 = requireTarget2(args5, "campaign");
|
|
21440
|
+
const payload = campaignUpdatePayloadFromFlags(args5, target4, loadJsonFileArg2(args5.file));
|
|
21441
|
+
await stageOp({ kind: "campaign.update", accountId, target: target4, payload });
|
|
21358
21442
|
}
|
|
21359
21443
|
});
|
|
21360
21444
|
function statusSugarCommand(entity, kind, name) {
|
|
@@ -21501,11 +21585,11 @@ Examples:
|
|
|
21501
21585
|
file: { type: "string", description: "JSON file with the full payload; flags override file keys" }
|
|
21502
21586
|
},
|
|
21503
21587
|
run: async ({ args: args5, rawArgs }) => {
|
|
21504
|
-
const { accountId, target:
|
|
21588
|
+
const { accountId, target: target4 } = accountTrackingTarget(args5);
|
|
21505
21589
|
await stageOp({
|
|
21506
21590
|
kind: "trackingParams.set",
|
|
21507
21591
|
accountId,
|
|
21508
|
-
target:
|
|
21592
|
+
target: target4,
|
|
21509
21593
|
payload: trackingParamsPayload(args5, rawArgs)
|
|
21510
21594
|
});
|
|
21511
21595
|
}
|
|
@@ -21793,7 +21877,7 @@ Examples:
|
|
|
21793
21877
|
campaign: args5.campaign,
|
|
21794
21878
|
content: Object.keys(content).length > 0 ? content : void 0
|
|
21795
21879
|
});
|
|
21796
|
-
await stageLinkedinOps(targets.map((
|
|
21880
|
+
await stageLinkedinOps(targets.map((target4) => ({ kind: "creative.update", accountId, target: target4, payload })));
|
|
21797
21881
|
}
|
|
21798
21882
|
});
|
|
21799
21883
|
var AUDIENCE_TYPES2 = ["company-list", "user-list", "retargeting", "engagement"];
|
|
@@ -21817,7 +21901,7 @@ Example: baker ads linkedin audiences create --name "ABM Tier-1" --type company-
|
|
|
21817
21901
|
},
|
|
21818
21902
|
run: async ({ args: args5 }) => {
|
|
21819
21903
|
const accountId = bareAccountId(args5);
|
|
21820
|
-
const
|
|
21904
|
+
const list3 = parseListFileArg(args5["list-file"], INLINE_ROWS_MAX);
|
|
21821
21905
|
const raw = args5.file ? loadJsonFileArg2(args5.file) : void 0;
|
|
21822
21906
|
await stageOp({
|
|
21823
21907
|
kind: "audience.create",
|
|
@@ -21825,7 +21909,7 @@ Example: baker ads linkedin audiences create --name "ABM Tier-1" --type company-
|
|
|
21825
21909
|
payload: {
|
|
21826
21910
|
name: args5.name,
|
|
21827
21911
|
audienceType: args5.type,
|
|
21828
|
-
...
|
|
21912
|
+
...list3 ? { listColumns: list3.columns, listRows: list3.rows } : {},
|
|
21829
21913
|
...raw ? { raw } : {}
|
|
21830
21914
|
}
|
|
21831
21915
|
});
|
|
@@ -21844,8 +21928,8 @@ Example: baker ads linkedin audiences upload urn:li:dmpSegment:42 --list-file mo
|
|
|
21844
21928
|
},
|
|
21845
21929
|
run: async ({ args: args5 }) => {
|
|
21846
21930
|
const accountId = bareAccountId(args5);
|
|
21847
|
-
const
|
|
21848
|
-
if (!
|
|
21931
|
+
const list3 = parseListFileArg(args5["list-file"], INLINE_ROWS_MAX);
|
|
21932
|
+
if (!list3) {
|
|
21849
21933
|
failWriteValidation2("--list-file is required");
|
|
21850
21934
|
}
|
|
21851
21935
|
await stageOp({
|
|
@@ -21853,8 +21937,8 @@ Example: baker ads linkedin audiences upload urn:li:dmpSegment:42 --list-file mo
|
|
|
21853
21937
|
accountId,
|
|
21854
21938
|
payload: {
|
|
21855
21939
|
segment: requireTarget2(args5, "audience segment"),
|
|
21856
|
-
listColumns:
|
|
21857
|
-
listRows:
|
|
21940
|
+
listColumns: list3.columns,
|
|
21941
|
+
listRows: list3.rows
|
|
21858
21942
|
}
|
|
21859
21943
|
});
|
|
21860
21944
|
}
|
|
@@ -26050,11 +26134,11 @@ function requireTarget3(args5, entity) {
|
|
|
26050
26134
|
failWriteValidation3(inverted);
|
|
26051
26135
|
}
|
|
26052
26136
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
26053
|
-
const
|
|
26054
|
-
if (typeof
|
|
26137
|
+
const target4 = args5.id ?? args5.target ?? args5.ref ?? positional;
|
|
26138
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
26055
26139
|
failWriteValidation3(`pass the ${entity} id as the positional argument`);
|
|
26056
26140
|
}
|
|
26057
|
-
return
|
|
26141
|
+
return target4;
|
|
26058
26142
|
}
|
|
26059
26143
|
async function stageOp2(raw) {
|
|
26060
26144
|
const preflight = metaDraftOpInputSchema.safeParse(raw);
|
|
@@ -28243,13 +28327,13 @@ async function resolveXAccountId(args5) {
|
|
|
28243
28327
|
});
|
|
28244
28328
|
process.exit(1);
|
|
28245
28329
|
}
|
|
28246
|
-
const
|
|
28330
|
+
const list3 = accounts.map((a) => ` ${a.id} ${a.name}`).join("\n");
|
|
28247
28331
|
writeAdsJson({
|
|
28248
28332
|
ok: false,
|
|
28249
28333
|
error: {
|
|
28250
28334
|
code: "MULTIPLE_ACCOUNTS",
|
|
28251
28335
|
message: `Multiple X Ads accounts found. Pass --account-id or set BAKER_X_ADS_ACCOUNT_ID:
|
|
28252
|
-
${
|
|
28336
|
+
${list3}`
|
|
28253
28337
|
}
|
|
28254
28338
|
});
|
|
28255
28339
|
process.exit(1);
|
|
@@ -30336,10 +30420,10 @@ function wallClockAsUtc(instant, timeZone) {
|
|
|
30336
30420
|
}
|
|
30337
30421
|
function accountMidnightIso(daysAgo, timeZone, now = /* @__PURE__ */ new Date()) {
|
|
30338
30422
|
const localNow = new Date(wallClockAsUtc(now, timeZone));
|
|
30339
|
-
const
|
|
30340
|
-
let instant =
|
|
30423
|
+
const target4 = Date.UTC(localNow.getUTCFullYear(), localNow.getUTCMonth(), localNow.getUTCDate() - daysAgo, 0, 0, 0);
|
|
30424
|
+
let instant = target4;
|
|
30341
30425
|
for (let i = 0; i < 2; i++) {
|
|
30342
|
-
instant =
|
|
30426
|
+
instant = target4 - (wallClockAsUtc(new Date(instant), timeZone) - instant);
|
|
30343
30427
|
}
|
|
30344
30428
|
return isoSeconds(new Date(instant));
|
|
30345
30429
|
}
|
|
@@ -31849,12 +31933,12 @@ function setFromRename(args5, existing) {
|
|
|
31849
31933
|
}
|
|
31850
31934
|
function conversionsWrite(args5, existing) {
|
|
31851
31935
|
const set = [...setFromEvents(args5, existing), ...setFromRename(args5, existing)];
|
|
31852
|
-
const
|
|
31936
|
+
const remove2 = [
|
|
31853
31937
|
...args5.removeKeys,
|
|
31854
31938
|
...args5.removeName === void 0 ? [] : under(args5.removeName, existing).map((row) => row.eventKey)
|
|
31855
31939
|
];
|
|
31856
|
-
if (set.length === 0 &&
|
|
31857
|
-
return { ...set.length > 0 ? { set } : {}, ...
|
|
31940
|
+
if (set.length === 0 && remove2.length === 0) return null;
|
|
31941
|
+
return { ...set.length > 0 ? { set } : {}, ...remove2.length > 0 ? { remove: remove2 } : {} };
|
|
31858
31942
|
}
|
|
31859
31943
|
|
|
31860
31944
|
// src/commands/analytics/conversionHints.ts
|
|
@@ -31917,9 +32001,9 @@ function mergeStoredWithCounts(stored, reported) {
|
|
|
31917
32001
|
const counts = new Map(reported.map((row) => [row.name, row]));
|
|
31918
32002
|
const groups = /* @__PURE__ */ new Map();
|
|
31919
32003
|
for (const row of stored) {
|
|
31920
|
-
const
|
|
31921
|
-
|
|
31922
|
-
groups.set(row.name,
|
|
32004
|
+
const group2 = groups.get(row.name) ?? [];
|
|
32005
|
+
group2.push(row);
|
|
32006
|
+
groups.set(row.name, group2);
|
|
31923
32007
|
}
|
|
31924
32008
|
return [...groups.entries()].map(([name, rows]) => {
|
|
31925
32009
|
const modes = new Set(rows.map((row) => row.countMode));
|
|
@@ -32719,7 +32803,7 @@ import { defineCommand as defineCommand97 } from "citty";
|
|
|
32719
32803
|
var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
|
|
32720
32804
|
function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
32721
32805
|
const set = parseSetFlags(raw, argv, now);
|
|
32722
|
-
const
|
|
32806
|
+
const remove2 = onlyOnce(raw.remove, "--remove", argv);
|
|
32723
32807
|
const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
32724
32808
|
if (days2 !== void 0 && (!Number.isInteger(days2) || days2 <= 0 || days2 > 400)) {
|
|
32725
32809
|
throw new ConversionArgsError("--days must be a whole number of days, from 1 to 400.");
|
|
@@ -32735,7 +32819,7 @@ function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
|
32735
32819
|
}
|
|
32736
32820
|
return {
|
|
32737
32821
|
...set === void 0 ? {} : { set },
|
|
32738
|
-
...
|
|
32822
|
+
...remove2 === void 0 ? {} : { remove: remove2 },
|
|
32739
32823
|
...days2 === void 0 ? {} : { days: days2 },
|
|
32740
32824
|
...uploads === void 0 ? {} : { uploads },
|
|
32741
32825
|
...raw.failed === true ? { failedOnly: true } : {},
|
|
@@ -35884,14 +35968,14 @@ function undisambiguatedSubsets(faces) {
|
|
|
35884
35968
|
}
|
|
35885
35969
|
function suggestFamilies(wanted, catalogue, limit2 = 5) {
|
|
35886
35970
|
const key = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
35887
|
-
const
|
|
35888
|
-
if (!
|
|
35889
|
-
const words2 =
|
|
35971
|
+
const target4 = key(wanted);
|
|
35972
|
+
if (!target4) return [];
|
|
35973
|
+
const words2 = target4.split(" ");
|
|
35890
35974
|
const scored = catalogue.map((family) => {
|
|
35891
35975
|
const candidate = key(family);
|
|
35892
|
-
if (candidate ===
|
|
35893
|
-
if (candidate.startsWith(
|
|
35894
|
-
if (candidate.includes(
|
|
35976
|
+
if (candidate === target4) return { family, score: 0 };
|
|
35977
|
+
if (candidate.startsWith(target4)) return { family, score: 1 };
|
|
35978
|
+
if (candidate.includes(target4)) return { family, score: 2 };
|
|
35895
35979
|
const shared = words2.filter((w) => w.length > 2 && candidate.includes(w)).length;
|
|
35896
35980
|
return { family, score: shared > 0 ? 3 + (words2.length - shared) : Number.POSITIVE_INFINITY };
|
|
35897
35981
|
}).filter((c) => Number.isFinite(c.score)).sort((a, b) => a.score - b.score || a.family.localeCompare(b.family));
|
|
@@ -35952,8 +36036,8 @@ async function resolveBrandFaces(family, weights, subsets, deps, styles = ["norm
|
|
|
35952
36036
|
function rebaseFontFaceSrc(block2, fromDir, toDir = "src/styles") {
|
|
35953
36037
|
return block2.replace(/url\(\s*(['"]?)([^'")]+)\1\s*\)/gi, (whole, _quote, href) => {
|
|
35954
36038
|
if (!isRepoFontHref(href)) return whole;
|
|
35955
|
-
const
|
|
35956
|
-
return `url('${posix.relative(toDir,
|
|
36039
|
+
const target4 = posix.normalize(posix.join(fromDir, href));
|
|
36040
|
+
return `url('${posix.relative(toDir, target4)}')`;
|
|
35957
36041
|
});
|
|
35958
36042
|
}
|
|
35959
36043
|
function declaredFontFaces(source) {
|
|
@@ -36131,12 +36215,12 @@ function declaredWeights(body) {
|
|
|
36131
36215
|
return range;
|
|
36132
36216
|
}
|
|
36133
36217
|
function selfHostedWeights(css, family) {
|
|
36134
|
-
const
|
|
36218
|
+
const target4 = normalizeFamily(family);
|
|
36135
36219
|
const weights = /* @__PURE__ */ new Set();
|
|
36136
36220
|
for (const rule of stripCssComments(css).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36137
36221
|
const body = rule[1] ?? "";
|
|
36138
36222
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36139
|
-
if (!declared || normalizeFamily(declared) !==
|
|
36223
|
+
if (!declared || normalizeFamily(declared) !== target4) continue;
|
|
36140
36224
|
for (const weight of declaredWeights(body)) weights.add(weight);
|
|
36141
36225
|
}
|
|
36142
36226
|
return [...weights].sort((a, b) => a - b);
|
|
@@ -36146,12 +36230,12 @@ function fontFileSubset(href) {
|
|
|
36146
36230
|
return /^[A-Za-z0-9]+-[1-9]00(?:italic)?-([\w-]+)\.woff2$/.exec(file)?.[1] ?? null;
|
|
36147
36231
|
}
|
|
36148
36232
|
function selfHostedSubsets(css, family) {
|
|
36149
|
-
const
|
|
36233
|
+
const target4 = normalizeFamily(family);
|
|
36150
36234
|
const subsets = /* @__PURE__ */ new Set();
|
|
36151
36235
|
for (const rule of stripCssComments(css).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36152
36236
|
const body = rule[1] ?? "";
|
|
36153
36237
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36154
|
-
if (!declared || normalizeFamily(declared) !==
|
|
36238
|
+
if (!declared || normalizeFamily(declared) !== target4) continue;
|
|
36155
36239
|
for (const url of body.matchAll(/url\(\s*['"]?([^'")]+)['"]?\s*\)/gi)) {
|
|
36156
36240
|
const subset = fontFileSubset(url[1] ?? "");
|
|
36157
36241
|
if (subset) subsets.add(subset);
|
|
@@ -36160,12 +36244,12 @@ function selfHostedSubsets(css, family) {
|
|
|
36160
36244
|
return [...subsets].sort();
|
|
36161
36245
|
}
|
|
36162
36246
|
function selfHostedStyles(css, family) {
|
|
36163
|
-
const
|
|
36247
|
+
const target4 = normalizeFamily(family);
|
|
36164
36248
|
const styles = /* @__PURE__ */ new Set();
|
|
36165
36249
|
for (const rule of stripCssComments(css).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36166
36250
|
const body = rule[1] ?? "";
|
|
36167
36251
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36168
|
-
if (declared && normalizeFamily(declared) ===
|
|
36252
|
+
if (declared && normalizeFamily(declared) === target4) styles.add(faceStyle(body));
|
|
36169
36253
|
}
|
|
36170
36254
|
return [...styles].sort();
|
|
36171
36255
|
}
|
|
@@ -36189,12 +36273,12 @@ function unresolvedBrandFamilies(css) {
|
|
|
36189
36273
|
return declared.filter((family) => !loaded.has(family)).map((family) => asAuthored(css, family));
|
|
36190
36274
|
}
|
|
36191
36275
|
function stripFontFaceBlocks(source, family, styles) {
|
|
36192
|
-
const
|
|
36276
|
+
const target4 = normalizeFamily(family);
|
|
36193
36277
|
const ranges = [];
|
|
36194
36278
|
for (const rule of stripCssComments(source).matchAll(/@font-face\s*\{([^}]*)\}/gi)) {
|
|
36195
36279
|
const body = rule[1] ?? "";
|
|
36196
36280
|
const declared = body.match(/font-family\s*:\s*([^;]+)/i)?.[1];
|
|
36197
|
-
if (!declared || normalizeFamily(declared) !==
|
|
36281
|
+
if (!declared || normalizeFamily(declared) !== target4 || rule.index === void 0) continue;
|
|
36198
36282
|
if (styles && !styles.has(faceStyle(body))) continue;
|
|
36199
36283
|
ranges.push([rule.index, rule.index + rule[0].length]);
|
|
36200
36284
|
}
|
|
@@ -36788,11 +36872,11 @@ function scoreRetentionRisk(videoNodes) {
|
|
|
36788
36872
|
};
|
|
36789
36873
|
}
|
|
36790
36874
|
function scoreMechanismClarity(allPromptText) {
|
|
36791
|
-
const
|
|
36875
|
+
const clear2 = MECHANISM_CUE.test(allPromptText);
|
|
36792
36876
|
return {
|
|
36793
36877
|
dimension: "mechanism_clarity",
|
|
36794
|
-
score:
|
|
36795
|
-
note:
|
|
36878
|
+
score: clear2 ? 1 : 0.4,
|
|
36879
|
+
note: clear2 ? "states a mechanism/proof" : "no clear 'why it works' \u2014 add the mechanism"
|
|
36796
36880
|
};
|
|
36797
36881
|
}
|
|
36798
36882
|
function clamp01(n) {
|
|
@@ -36955,8 +37039,8 @@ function canvasOutputsRoot(canvasFile, cwd = process.cwd(), exists2 = existsSync
|
|
|
36955
37039
|
const root = findWorkspaceRoot(path5.dirname(path5.resolve(cwd, canvasFile)), exists2) ?? cwd;
|
|
36956
37040
|
return path5.join(root, "canvas");
|
|
36957
37041
|
}
|
|
36958
|
-
function canonicalize(
|
|
36959
|
-
const abs = path5.resolve(
|
|
37042
|
+
function canonicalize(target4) {
|
|
37043
|
+
const abs = path5.resolve(target4);
|
|
36960
37044
|
let dir = abs;
|
|
36961
37045
|
for (; ; ) {
|
|
36962
37046
|
try {
|
|
@@ -36969,19 +37053,19 @@ function canonicalize(target2) {
|
|
|
36969
37053
|
}
|
|
36970
37054
|
}
|
|
36971
37055
|
}
|
|
36972
|
-
function isInside(root,
|
|
36973
|
-
const rel = path5.relative(root,
|
|
37056
|
+
function isInside(root, target4) {
|
|
37057
|
+
const rel = path5.relative(root, target4);
|
|
36974
37058
|
return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
36975
37059
|
}
|
|
36976
|
-
function toCanvasRelative(canvasDir,
|
|
36977
|
-
return path5.relative(canvasDir,
|
|
37060
|
+
function toCanvasRelative(canvasDir, target4) {
|
|
37061
|
+
return path5.relative(canvasDir, target4).split(path5.sep).join("/");
|
|
36978
37062
|
}
|
|
36979
37063
|
var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
|
|
36980
37064
|
function rewriteTarget(value, workspaceRoot) {
|
|
36981
37065
|
if (typeof value !== "string" || value.length === 0) return null;
|
|
36982
37066
|
if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path5.isAbsolute(value)) return null;
|
|
36983
|
-
const
|
|
36984
|
-
if (isInside(workspaceRoot,
|
|
37067
|
+
const target4 = canonicalize(value);
|
|
37068
|
+
if (isInside(workspaceRoot, target4)) return target4;
|
|
36985
37069
|
const fromRuntime = path5.relative(RUNTIME_WORKSPACE_ROOT, path5.normalize(value));
|
|
36986
37070
|
if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path5.isAbsolute(fromRuntime)) {
|
|
36987
37071
|
return path5.join(workspaceRoot, fromRuntime);
|
|
@@ -37007,9 +37091,9 @@ function normalizeCanvasPaths(canvas, canvasDir, workspaceRoot) {
|
|
|
37007
37091
|
}
|
|
37008
37092
|
const key = localPathParam(n);
|
|
37009
37093
|
if (!key) return node;
|
|
37010
|
-
const
|
|
37011
|
-
if (
|
|
37012
|
-
const to = toCanvasRelative(dir,
|
|
37094
|
+
const target4 = rewriteTarget(params2[key], root);
|
|
37095
|
+
if (target4 === null) return node;
|
|
37096
|
+
const to = toCanvasRelative(dir, target4);
|
|
37013
37097
|
rewrites.push({ nodeId, param: key, from: params2[key], to });
|
|
37014
37098
|
return { ...node, params: { ...params2, [key]: to } };
|
|
37015
37099
|
});
|
|
@@ -37864,8 +37948,8 @@ function castAvatarsOnElements(elementsInput, avatars) {
|
|
|
37864
37948
|
if (!avatar) return el;
|
|
37865
37949
|
next += 1;
|
|
37866
37950
|
if (el.label) byLabel.set(el.label, avatar);
|
|
37867
|
-
const
|
|
37868
|
-
return { ...el, ...
|
|
37951
|
+
const description2 = avatar.subjectDescription?.trim();
|
|
37952
|
+
return { ...el, ...description2 ? { description: description2 } : {}, source_image: avatar.sheetUrl, source_is_sheet: true };
|
|
37869
37953
|
});
|
|
37870
37954
|
return cast.map((el) => {
|
|
37871
37955
|
const avatar = el.same_as ? byLabel.get(el.same_as) : void 0;
|
|
@@ -38160,7 +38244,7 @@ function buildFramePrompt(edge, sceneIndex, framePrompt, present2, hasAnchor, mo
|
|
|
38160
38244
|
"- ORIGINAL_FRAME \u2014 use ONLY for composition: framing, camera angle, shot size, subject placement, pose, and proportions. IGNORE its text, logo, brand name, colors, AND the identity of every person/animal/object in it \u2014 those come from the labeled reference images above, never from this frame. It is a DIFFERENT brand's footage with DIFFERENT actors, here ONLY to anchor where things sit and how the shot is framed (e.g. a profile/side angle stays a profile/side angle), never who they are or what palette to use."
|
|
38161
38245
|
] : []
|
|
38162
38246
|
].join("\n");
|
|
38163
|
-
const
|
|
38247
|
+
const description2 = framePrompt?.trim() || `the ${edge} frame of scene ${sceneIndex + 1} \u2014 describe the full composition, subjects, setting, action, lighting, and palette here. (Edit this line to change ONLY this frame.)`;
|
|
38164
38248
|
const isHookFrame = sceneIndex === 0 && edge === "start";
|
|
38165
38249
|
const cleanPlateBlock = [
|
|
38166
38250
|
"CRITICAL \u2014 RENDER A CLEAN PLATE WITH ZERO TEXT OR GRAPHIC OVERLAYS:",
|
|
@@ -38238,7 +38322,7 @@ function buildFramePrompt(edge, sceneIndex, framePrompt, present2, hasAnchor, mo
|
|
|
38238
38322
|
""
|
|
38239
38323
|
] : [],
|
|
38240
38324
|
"FRAME DESCRIPTION (this frame's editable prompt):",
|
|
38241
|
-
|
|
38325
|
+
description2,
|
|
38242
38326
|
"",
|
|
38243
38327
|
"Render exactly what the FRAME DESCRIPTION and the SHARED AD SPEC specify \u2014 this is the authoritative ad: its cast identity (via the reference images), palette, brand, and intent are law. Keep every recurring element identical to its reference image across all frames. Again: clean plate only \u2014 no rendered text, and no icons/stickers/emojis/badges (those live on the overlay layer).",
|
|
38244
38328
|
"",
|
|
@@ -39094,8 +39178,8 @@ function localizeNumeralsForNative(text2, langCode) {
|
|
|
39094
39178
|
if (!langCode || !INTEGER_SPELLERS[langCode]) return text2;
|
|
39095
39179
|
return text2.replace(/(?<![\w.,-])\d{1,9}(?![\w.,-])/g, (m) => spellNumber(langCode, Number.parseInt(m, 10)));
|
|
39096
39180
|
}
|
|
39097
|
-
function parseVoiceTraits(
|
|
39098
|
-
const d =
|
|
39181
|
+
function parseVoiceTraits(description2) {
|
|
39182
|
+
const d = description2.toLowerCase();
|
|
39099
39183
|
const out = {};
|
|
39100
39184
|
if (/\b(female|woman|women|girl|lady)\b/.test(d)) out.gender = "female";
|
|
39101
39185
|
else if (/\b(male|man|men|guy|boy)\b/.test(d)) out.gender = "male";
|
|
@@ -39306,11 +39390,11 @@ function makeVoiceFactory(blueprint, canonical2, nodes, voiceLanguage, pinnedVoi
|
|
|
39306
39390
|
const existing = bySpeaker.get(speaker);
|
|
39307
39391
|
if (existing) return existing;
|
|
39308
39392
|
const id = sanitizeId(`voice_${speaker}`, `voice_${bySpeaker.size}`);
|
|
39309
|
-
const
|
|
39310
|
-
const traits = parseVoiceTraits(
|
|
39393
|
+
const description2 = describe(speaker);
|
|
39394
|
+
const traits = parseVoiceTraits(description2);
|
|
39311
39395
|
if (voiceLanguage) traits.language = voiceLanguage;
|
|
39312
39396
|
nodes.push(
|
|
39313
|
-
pinnedVoiceId ? { id, type: "voice_select", params: { description, voice_id: pinnedVoiceId, ...traits } } : { id, type: "voice_select", params: { description, ...traits } }
|
|
39397
|
+
pinnedVoiceId ? { id, type: "voice_select", params: { description: description2, voice_id: pinnedVoiceId, ...traits } } : { id, type: "voice_select", params: { description: description2, ...traits } }
|
|
39314
39398
|
);
|
|
39315
39399
|
bySpeaker.set(speaker, id);
|
|
39316
39400
|
return id;
|
|
@@ -41312,8 +41396,8 @@ function mimeForFile(filePath) {
|
|
|
41312
41396
|
function toPosix(p) {
|
|
41313
41397
|
return p.split(path14.sep).join("/");
|
|
41314
41398
|
}
|
|
41315
|
-
function isInside2(dir,
|
|
41316
|
-
const rel = path14.relative(dir,
|
|
41399
|
+
function isInside2(dir, target4) {
|
|
41400
|
+
const rel = path14.relative(dir, target4);
|
|
41317
41401
|
return !rel.startsWith("..") && !path14.isAbsolute(rel);
|
|
41318
41402
|
}
|
|
41319
41403
|
function localPathRefsFromCanvas(parsed) {
|
|
@@ -41429,11 +41513,11 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
41429
41513
|
if (path14.isAbsolute(entry.path) || entry.path.split("/").includes("..")) {
|
|
41430
41514
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
41431
41515
|
}
|
|
41432
|
-
const
|
|
41433
|
-
if (
|
|
41516
|
+
const target4 = path14.resolve(resolvedTarget, entry.path);
|
|
41517
|
+
if (target4 !== resolvedTarget && !target4.startsWith(resolvedTarget + path14.sep)) {
|
|
41434
41518
|
throw new Error(`snapshot entry escapes the creative directory: ${entry.path}`);
|
|
41435
41519
|
}
|
|
41436
|
-
const existing = await readFile10(
|
|
41520
|
+
const existing = await readFile10(target4).catch(() => null);
|
|
41437
41521
|
if (existing) {
|
|
41438
41522
|
if (sha256Hex(existing) === entry.sha256) {
|
|
41439
41523
|
upToDate.push(entry.path);
|
|
@@ -41444,19 +41528,19 @@ async function restoreRunSnapshot(manifest, targetDir, opts = {}) {
|
|
|
41444
41528
|
continue;
|
|
41445
41529
|
}
|
|
41446
41530
|
}
|
|
41447
|
-
planned.push({ entry, target:
|
|
41531
|
+
planned.push({ entry, target: target4 });
|
|
41448
41532
|
}
|
|
41449
41533
|
if (conflicts.length > 0) throw new SnapshotConflictError(conflicts);
|
|
41450
41534
|
const restored = [];
|
|
41451
|
-
for (const { entry, target:
|
|
41535
|
+
for (const { entry, target: target4 } of planned) {
|
|
41452
41536
|
const res = await fetch(entry.url);
|
|
41453
41537
|
if (!res.ok) throw new Error(`snapshot download failed for ${entry.path}: ${res.status} ${res.statusText}`);
|
|
41454
41538
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
41455
41539
|
if (sha256Hex(bytes) !== entry.sha256) {
|
|
41456
41540
|
throw new Error(`snapshot download for ${entry.path} does not match its recorded sha256`);
|
|
41457
41541
|
}
|
|
41458
|
-
await mkdir5(path14.dirname(
|
|
41459
|
-
await writeFile7(
|
|
41542
|
+
await mkdir5(path14.dirname(target4), { recursive: true });
|
|
41543
|
+
await writeFile7(target4, bytes);
|
|
41460
41544
|
restored.push(entry.path);
|
|
41461
41545
|
}
|
|
41462
41546
|
return { canvasPath: path14.resolve(resolvedTarget, manifest.canvas.path), restored, upToDate };
|
|
@@ -42602,8 +42686,8 @@ function castAvatarsOnStaticElements(elementsInput, avatars) {
|
|
|
42602
42686
|
const avatar = isPerson(el) ? avatars[next] : void 0;
|
|
42603
42687
|
if (!avatar) return el;
|
|
42604
42688
|
next += 1;
|
|
42605
|
-
const
|
|
42606
|
-
return { ...el, ...
|
|
42689
|
+
const description2 = avatar.subjectDescription?.trim();
|
|
42690
|
+
return { ...el, ...description2 ? { description: description2 } : {}, source_image: avatar.sheetUrl };
|
|
42607
42691
|
});
|
|
42608
42692
|
}
|
|
42609
42693
|
function staticAvatarsNotCast(elementsInput, handles) {
|
|
@@ -43126,9 +43210,9 @@ async function resolveCastAvatars(flag3) {
|
|
|
43126
43210
|
}
|
|
43127
43211
|
|
|
43128
43212
|
// src/commands/canvas/scaffold-static-ad.ts
|
|
43129
|
-
async function fileExists(
|
|
43213
|
+
async function fileExists(target4) {
|
|
43130
43214
|
try {
|
|
43131
|
-
await access(
|
|
43215
|
+
await access(target4);
|
|
43132
43216
|
return true;
|
|
43133
43217
|
} catch {
|
|
43134
43218
|
return false;
|
|
@@ -43854,8 +43938,8 @@ function beatSeconds(line, videoModel) {
|
|
|
43854
43938
|
}
|
|
43855
43939
|
var BRAND_PLATE = "A solid flat brand colour plate \u2014 an end card. No people, no objects, no scenery, no text of any kind.";
|
|
43856
43940
|
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;
|
|
43857
|
-
function briefWantsLegibleText(
|
|
43858
|
-
return ASKS_FOR_LEGIBLE.test(
|
|
43941
|
+
function briefWantsLegibleText(show2) {
|
|
43942
|
+
return ASKS_FOR_LEGIBLE.test(show2);
|
|
43859
43943
|
}
|
|
43860
43944
|
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ÁÉÍÓÚÑ]/;
|
|
43861
43945
|
function lineIntroducesSpeaker(line) {
|
|
@@ -43909,8 +43993,8 @@ function adSpecCastElements(spec, avatar) {
|
|
|
43909
43993
|
...spec.set?.image?.trim() ? { source_image: spec.set.image.trim() } : {}
|
|
43910
43994
|
});
|
|
43911
43995
|
}
|
|
43912
|
-
const
|
|
43913
|
-
if (!
|
|
43996
|
+
const description2 = (avatar?.subjectDescription ?? spec.cast?.description)?.trim();
|
|
43997
|
+
if (!description2) return elements;
|
|
43914
43998
|
const scenes = spec.beats.map((beat, i) => ({ beat, i })).filter(({ beat, i }) => beat.cast !== false && !(endCardWanted(spec) && i === lastIndex)).map(({ i }) => i);
|
|
43915
43999
|
if (scenes.length === 0) return elements;
|
|
43916
44000
|
const sheet = avatar?.sheetUrl?.trim();
|
|
@@ -43920,7 +44004,7 @@ function adSpecCastElements(spec, avatar) {
|
|
|
43920
44004
|
// Same id the dialogue names as speaker: that pairing is what lets the engine see
|
|
43921
44005
|
// the presenter as present in a scene and route it to native audio.
|
|
43922
44006
|
cast_id: AD_CAST_ID,
|
|
43923
|
-
description,
|
|
44007
|
+
description: description2,
|
|
43924
44008
|
scenes,
|
|
43925
44009
|
// An avatar's identity sheet IS the turnaround the engine would otherwise render,
|
|
43926
44010
|
// so it is handed over as one. Left unmarked, the run paid to generate a sheet OF
|
|
@@ -44530,7 +44614,7 @@ var scaffoldAdCommand = defineCommand115({
|
|
|
44530
44614
|
if (flagAvatar) {
|
|
44531
44615
|
spec.data.cast = { ...spec.data.cast, avatar: flagAvatar };
|
|
44532
44616
|
}
|
|
44533
|
-
const contradicts = spec.data.beats.map((beat, i) => ({ i, show: beat.show })).filter(({ show }) => briefWantsLegibleText(
|
|
44617
|
+
const contradicts = spec.data.beats.map((beat, i) => ({ i, show: beat.show })).filter(({ show: show2 }) => briefWantsLegibleText(show2));
|
|
44534
44618
|
if (contradicts.length > 0) {
|
|
44535
44619
|
writeJson({
|
|
44536
44620
|
ok: false,
|
|
@@ -45214,8 +45298,8 @@ function referenceVideoExt(url, contentType) {
|
|
|
45214
45298
|
const mime = (contentType ?? "").split(";")[0]?.trim().toLowerCase();
|
|
45215
45299
|
return mime && VIDEO_EXT_BY_MIME[mime] || ".mp4";
|
|
45216
45300
|
}
|
|
45217
|
-
async function fileExists2(
|
|
45218
|
-
return access2(
|
|
45301
|
+
async function fileExists2(target4) {
|
|
45302
|
+
return access2(target4).then(
|
|
45219
45303
|
() => true,
|
|
45220
45304
|
() => false
|
|
45221
45305
|
);
|
|
@@ -46533,8 +46617,8 @@ async function importedFiles(text2, file, root) {
|
|
|
46533
46617
|
for (const match of text2.matchAll(re2)) {
|
|
46534
46618
|
const spec = match[1];
|
|
46535
46619
|
if (spec === void 0) continue;
|
|
46536
|
-
const
|
|
46537
|
-
if (
|
|
46620
|
+
const target4 = await resolveSpecifier(spec, file, root);
|
|
46621
|
+
if (target4 !== null) out.push(target4);
|
|
46538
46622
|
}
|
|
46539
46623
|
}
|
|
46540
46624
|
return out;
|
|
@@ -46552,8 +46636,8 @@ async function landingGraphFiles(root, slug) {
|
|
|
46552
46636
|
continue;
|
|
46553
46637
|
}
|
|
46554
46638
|
seen.add(file);
|
|
46555
|
-
for (const
|
|
46556
|
-
if (!seen.has(
|
|
46639
|
+
for (const target4 of await importedFiles(text2, file, root)) {
|
|
46640
|
+
if (!seen.has(target4)) queue.push(target4);
|
|
46557
46641
|
}
|
|
46558
46642
|
}
|
|
46559
46643
|
return new Set([...seen].map((abs) => path29.relative(root, abs).split(path29.sep).join("/")));
|
|
@@ -46676,8 +46760,8 @@ function repointMoved(text2, opts) {
|
|
|
46676
46760
|
return text2.replace(QUOTED_RELATIVE, (_match, quote, spec) => {
|
|
46677
46761
|
const abs = path31.resolve(opts.fromDir, spec);
|
|
46678
46762
|
const within = path31.relative(opts.movedFrom, abs);
|
|
46679
|
-
const
|
|
46680
|
-
return `${quote}${toSpecifier(opts.toDir,
|
|
46763
|
+
const target4 = within.startsWith("..") || path31.isAbsolute(within) ? abs : path31.resolve(opts.movedTo, within);
|
|
46764
|
+
return `${quote}${toSpecifier(opts.toDir, target4)}${quote}`;
|
|
46681
46765
|
});
|
|
46682
46766
|
}
|
|
46683
46767
|
|
|
@@ -46753,8 +46837,8 @@ function repointIntoArchive(text2, sourceAbs, destAbs, archivedBySource) {
|
|
|
46753
46837
|
const toDir = path32.dirname(destAbs);
|
|
46754
46838
|
return text2.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
|
|
46755
46839
|
const [specPath, suffix] = splitSuffix(spec);
|
|
46756
|
-
const
|
|
46757
|
-
const resolved = resolveInArchive(
|
|
46840
|
+
const target4 = path32.resolve(fromDir, specPath);
|
|
46841
|
+
const resolved = resolveInArchive(target4, archivedBySource) ?? resolveOnDisk(target4, isImportPosition(text2, offset));
|
|
46758
46842
|
if (resolved === null) return match;
|
|
46759
46843
|
const rel = posix2(path32.relative(toDir, resolved));
|
|
46760
46844
|
return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
|
|
@@ -46812,63 +46896,63 @@ async function promoteVariantFiles(opts) {
|
|
|
46812
46896
|
}
|
|
46813
46897
|
return written;
|
|
46814
46898
|
}
|
|
46815
|
-
function archiveRecord(
|
|
46899
|
+
function archiveRecord(target4, variantNumber) {
|
|
46816
46900
|
return `${JSON.stringify(
|
|
46817
46901
|
{
|
|
46818
|
-
experimentId:
|
|
46819
|
-
page:
|
|
46820
|
-
pageInternalId:
|
|
46821
|
-
variant:
|
|
46902
|
+
experimentId: target4.experimentId,
|
|
46903
|
+
page: target4.landingSlug,
|
|
46904
|
+
pageInternalId: target4.landingInternalId,
|
|
46905
|
+
variant: target4.variantSlug,
|
|
46822
46906
|
variantNumber,
|
|
46823
46907
|
// Which arm this snapshot is. On a control win the variant lost; on a
|
|
46824
46908
|
// variant win what lost is the page's own previous content, which never
|
|
46825
46909
|
// had a number of its own — so it is filed under the test that rejected
|
|
46826
46910
|
// it, which is the only number that means anything about it.
|
|
46827
|
-
arm:
|
|
46911
|
+
arm: target4.survivor === "variant" ? "page-before-this-test" : "variant"
|
|
46828
46912
|
},
|
|
46829
46913
|
null,
|
|
46830
46914
|
2
|
|
46831
46915
|
)}
|
|
46832
46916
|
`;
|
|
46833
46917
|
}
|
|
46834
|
-
async function foldExperiment(root,
|
|
46835
|
-
const pageDir = path32.resolve(root, "src/pages",
|
|
46836
|
-
const variantDir = path32.resolve(root, "src/pages",
|
|
46837
|
-
const variantNumber = variantNumberOf(
|
|
46918
|
+
async function foldExperiment(root, target4) {
|
|
46919
|
+
const pageDir = path32.resolve(root, "src/pages", target4.landingSlug);
|
|
46920
|
+
const variantDir = path32.resolve(root, "src/pages", target4.variantSlug);
|
|
46921
|
+
const variantNumber = variantNumberOf(target4.variantSlug);
|
|
46838
46922
|
if (variantNumber === null) {
|
|
46839
46923
|
return {
|
|
46840
|
-
error: `\u201C${
|
|
46924
|
+
error: `\u201C${target4.variantSlug}\u201D is not a variant of \u201C${target4.landingSlug}\u201D, so there is nothing to fold`
|
|
46841
46925
|
};
|
|
46842
46926
|
}
|
|
46843
46927
|
if (!await isDir(pageDir)) {
|
|
46844
|
-
return { error: `There is no page at src/pages/${
|
|
46928
|
+
return { error: `There is no page at src/pages/${target4.landingSlug}/` };
|
|
46845
46929
|
}
|
|
46846
46930
|
if (!await isDir(variantDir)) {
|
|
46847
|
-
return { error: `src/pages/${
|
|
46931
|
+
return { error: `src/pages/${target4.variantSlug}/ is already gone \u2014 this test looks folded in already` };
|
|
46848
46932
|
}
|
|
46849
|
-
const archiveKey =
|
|
46933
|
+
const archiveKey = target4.landingInternalId ?? target4.landingSlug;
|
|
46850
46934
|
const archiveDir = path32.resolve(root, ARCHIVE_ROOT, archiveKey, String(variantNumber));
|
|
46851
46935
|
await rm8(archiveDir, { recursive: true, force: true });
|
|
46852
46936
|
await mkdir9(archiveDir, { recursive: true });
|
|
46853
46937
|
const written = await archiveArm({
|
|
46854
46938
|
root,
|
|
46855
|
-
armDir:
|
|
46939
|
+
armDir: target4.survivor === "variant" ? pageDir : variantDir,
|
|
46856
46940
|
pageDir,
|
|
46857
46941
|
archiveDir,
|
|
46858
|
-
armSlug:
|
|
46942
|
+
armSlug: target4.survivor === "variant" ? target4.landingSlug : target4.variantSlug
|
|
46859
46943
|
});
|
|
46860
|
-
await writeFile12(path32.join(archiveDir, "_variant.json"), archiveRecord(
|
|
46944
|
+
await writeFile12(path32.join(archiveDir, "_variant.json"), archiveRecord(target4, variantNumber), "utf8");
|
|
46861
46945
|
written.push(posix2(path32.join(ARCHIVE_ROOT, archiveKey, String(variantNumber), "_variant.json")));
|
|
46862
|
-
if (
|
|
46946
|
+
if (target4.survivor === "variant") {
|
|
46863
46947
|
written.push(...await promoteVariantFiles({ root, pageDir, variantDir }));
|
|
46864
46948
|
}
|
|
46865
46949
|
await rm8(variantDir, { recursive: true, force: true });
|
|
46866
46950
|
return {
|
|
46867
|
-
experimentId:
|
|
46868
|
-
page:
|
|
46951
|
+
experimentId: target4.experimentId,
|
|
46952
|
+
page: target4.landingSlug,
|
|
46869
46953
|
archivedTo: posix2(path32.join(ARCHIVE_ROOT, archiveKey, String(variantNumber))),
|
|
46870
46954
|
written,
|
|
46871
|
-
removed: [`src/pages/${
|
|
46955
|
+
removed: [`src/pages/${target4.variantSlug}`]
|
|
46872
46956
|
};
|
|
46873
46957
|
}
|
|
46874
46958
|
|
|
@@ -48372,9 +48456,9 @@ var foldCommand = defineCommand124({
|
|
|
48372
48456
|
}
|
|
48373
48457
|
const folded = [];
|
|
48374
48458
|
const failures = [];
|
|
48375
|
-
for (const
|
|
48376
|
-
const result = await foldExperiment(process.cwd(),
|
|
48377
|
-
if ("error" in result) failures.push(`${
|
|
48459
|
+
for (const target4 of owed) {
|
|
48460
|
+
const result = await foldExperiment(process.cwd(), target4);
|
|
48461
|
+
if ("error" in result) failures.push(`${target4.landingSlug}: ${result.error}`);
|
|
48378
48462
|
else folded.push(result);
|
|
48379
48463
|
}
|
|
48380
48464
|
if (folded.length > 0) {
|
|
@@ -48916,6 +49000,9 @@ var ADS_MATCHING = [
|
|
|
48916
49000
|
"country"
|
|
48917
49001
|
];
|
|
48918
49002
|
var MAPPING_SLOTS = {
|
|
49003
|
+
shopifyCustomer: [
|
|
49004
|
+
{ kind: "record", key: "customer", allowed: ["email", "phone", "acceptsEmailMarketing", "acceptsSmsMarketing"] }
|
|
49005
|
+
],
|
|
48919
49006
|
googleSpreadsheet: [{ kind: "list", key: "columnMapping", addressedBy: "column" }],
|
|
48920
49007
|
hubspotForm: [
|
|
48921
49008
|
{
|
|
@@ -49157,9 +49244,9 @@ function listPatch(shape, sideEffect, entries) {
|
|
|
49157
49244
|
function existingEntries(shape, sideEffect) {
|
|
49158
49245
|
const owner = shape.under ? sideEffect[shape.under] : sideEffect;
|
|
49159
49246
|
if (!owner || typeof owner !== "object") return [];
|
|
49160
|
-
const
|
|
49161
|
-
if (!Array.isArray(
|
|
49162
|
-
return
|
|
49247
|
+
const list3 = owner[shape.key];
|
|
49248
|
+
if (!Array.isArray(list3)) return [];
|
|
49249
|
+
return list3.filter((entry) => Boolean(entry) && typeof entry === "object");
|
|
49163
49250
|
}
|
|
49164
49251
|
function mergeEntries(shape, existing, incoming) {
|
|
49165
49252
|
const address = (entry) => {
|
|
@@ -49660,10 +49747,10 @@ function dropUnsetOptionals(sideEffect, path49) {
|
|
|
49660
49747
|
return [{ path: path49, change: `dropped \`${key}\` (an optional string is absent, never null)` }];
|
|
49661
49748
|
});
|
|
49662
49749
|
}
|
|
49663
|
-
function fillNulledArrays(
|
|
49750
|
+
function fillNulledArrays(target4, prefix, path49) {
|
|
49664
49751
|
return ARRAY_FIELDS.flatMap((key) => {
|
|
49665
|
-
if (!(key in
|
|
49666
|
-
|
|
49752
|
+
if (!(key in target4) || target4[key] !== null) return [];
|
|
49753
|
+
target4[key] = [];
|
|
49667
49754
|
return [{ path: path49, change: `\`${prefix}${key}: null\` \u2192 \`[]\`` }];
|
|
49668
49755
|
});
|
|
49669
49756
|
}
|
|
@@ -49689,9 +49776,9 @@ function sideEffectsOf(node) {
|
|
|
49689
49776
|
function normalizeSideEffect(sideEffect, where) {
|
|
49690
49777
|
const path49 = `${where} \u2192 ${String(sideEffect.id ?? "side effect")}`;
|
|
49691
49778
|
const arrays = ARRAY_OWNERS.flatMap((owner) => {
|
|
49692
|
-
const
|
|
49693
|
-
if (!
|
|
49694
|
-
return fillNulledArrays(
|
|
49779
|
+
const target4 = owner ? sideEffect[owner] : sideEffect;
|
|
49780
|
+
if (!target4 || typeof target4 !== "object") return [];
|
|
49781
|
+
return fillNulledArrays(target4, owner ? `${owner}.` : "", path49);
|
|
49695
49782
|
});
|
|
49696
49783
|
return [...dropUnsetOptionals(sideEffect, path49), ...arrays, ...tidyEmailRecipients(sideEffect, path49)];
|
|
49697
49784
|
}
|
|
@@ -50881,13 +50968,13 @@ async function resolvePropertyId(args5) {
|
|
|
50881
50968
|
if (properties.length === 0) {
|
|
50882
50969
|
handleConnectionError("ga4");
|
|
50883
50970
|
}
|
|
50884
|
-
const
|
|
50971
|
+
const list3 = properties.map((p) => ` ${p.externalId} ${p.name}`).join("\n");
|
|
50885
50972
|
writeJsonEnvelope({
|
|
50886
50973
|
ok: false,
|
|
50887
50974
|
error: {
|
|
50888
50975
|
code: "MULTIPLE_PROPERTIES",
|
|
50889
50976
|
message: `Multiple properties found. Pass --property-id or set BAKER_GA4_PROPERTY_ID:
|
|
50890
|
-
${
|
|
50977
|
+
${list3}`
|
|
50891
50978
|
}
|
|
50892
50979
|
});
|
|
50893
50980
|
process.exit(1);
|
|
@@ -50980,11 +51067,11 @@ function failValidation3(message) {
|
|
|
50980
51067
|
}
|
|
50981
51068
|
function requireTarget5(args5, entity) {
|
|
50982
51069
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
50983
|
-
const
|
|
50984
|
-
if (typeof
|
|
51070
|
+
const target4 = args5.id ?? args5.target ?? positional;
|
|
51071
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
50985
51072
|
failValidation3(`pass the ${entity} id as the positional argument`);
|
|
50986
51073
|
}
|
|
50987
|
-
return
|
|
51074
|
+
return target4;
|
|
50988
51075
|
}
|
|
50989
51076
|
function readJsonSource(args5, flag3) {
|
|
50990
51077
|
const inline = args5[flag3];
|
|
@@ -51978,11 +52065,11 @@ Examples:
|
|
|
51978
52065
|
"property-id": propertyArg
|
|
51979
52066
|
},
|
|
51980
52067
|
run: async ({ args: args5 }) => {
|
|
51981
|
-
const
|
|
52068
|
+
const target4 = requireTarget5(args5, "audience id");
|
|
51982
52069
|
const payload = loadJsonArg(args5);
|
|
51983
52070
|
await stageOp3({
|
|
51984
52071
|
kind: "ga4.audience.update",
|
|
51985
|
-
target:
|
|
52072
|
+
target: target4,
|
|
51986
52073
|
payload,
|
|
51987
52074
|
...withProperty(args5)
|
|
51988
52075
|
});
|
|
@@ -52111,13 +52198,13 @@ Examples:
|
|
|
52111
52198
|
"property-id": propertyArg
|
|
52112
52199
|
},
|
|
52113
52200
|
run: async ({ args: args5 }) => {
|
|
52114
|
-
const
|
|
52201
|
+
const target4 = requireTarget5(args5, "Google Ads link id");
|
|
52115
52202
|
if (typeof args5["ads-personalization"] !== "string") {
|
|
52116
52203
|
failValidation3("pass --ads-personalization true|false \u2014 it is the only thing a link update can change");
|
|
52117
52204
|
}
|
|
52118
52205
|
await stageOp3({
|
|
52119
52206
|
kind: "ga4.googleAdsLink.update",
|
|
52120
|
-
target:
|
|
52207
|
+
target: target4,
|
|
52121
52208
|
payload: { adsPersonalizationEnabled: booleanArg(args5["ads-personalization"], "ads-personalization") },
|
|
52122
52209
|
...withProperty(args5)
|
|
52123
52210
|
});
|
|
@@ -52352,13 +52439,13 @@ async function resolveSiteUrl(args5) {
|
|
|
52352
52439
|
if (sites.length === 0) {
|
|
52353
52440
|
handleConnectionError("gsc");
|
|
52354
52441
|
}
|
|
52355
|
-
const
|
|
52442
|
+
const list3 = sites.map((s) => ` ${s.siteUrl} (${s.permissionLevel})`).join("\n");
|
|
52356
52443
|
writeJsonEnvelope({
|
|
52357
52444
|
ok: false,
|
|
52358
52445
|
error: {
|
|
52359
52446
|
code: "MULTIPLE_SITES",
|
|
52360
52447
|
message: `Multiple sites found. Pass --site-url or set BAKER_GSC_SITE_URL:
|
|
52361
|
-
${
|
|
52448
|
+
${list3}`
|
|
52362
52449
|
}
|
|
52363
52450
|
});
|
|
52364
52451
|
process.exit(1);
|
|
@@ -53348,7 +53435,7 @@ function propertiesCommand2(object) {
|
|
|
53348
53435
|
object
|
|
53349
53436
|
});
|
|
53350
53437
|
const { properties } = response.data;
|
|
53351
|
-
const operators = Object.entries(HUBSPOT_OPERATORS).map(([kind,
|
|
53438
|
+
const operators = Object.entries(HUBSPOT_OPERATORS).map(([kind, list3]) => `${kind}: ${list3.map((operator) => operator.value).join(", ")}`).join(" \xB7 ");
|
|
53352
53439
|
const objectFlag = object === "contact" ? "" : ` --object ${object}`;
|
|
53353
53440
|
const hints2 = properties.length === 0 ? [`This account has no visible ${object} property, so there is nothing an event could watch.`] : [
|
|
53354
53441
|
`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.`
|
|
@@ -53932,17 +54019,17 @@ var dimensionsCommand = defineCommand147({
|
|
|
53932
54019
|
},
|
|
53933
54020
|
run: async ({ args: args5 }) => {
|
|
53934
54021
|
try {
|
|
53935
|
-
const
|
|
53936
|
-
if (!
|
|
54022
|
+
const target4 = args5.target;
|
|
54023
|
+
if (!target4) {
|
|
53937
54024
|
writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "target argument is required" } });
|
|
53938
54025
|
process.exit(1);
|
|
53939
54026
|
}
|
|
53940
|
-
const buffer = await readImageBuffer(
|
|
54027
|
+
const buffer = await readImageBuffer(target4);
|
|
53941
54028
|
const dims = getDimensionsFromBuffer(buffer);
|
|
53942
54029
|
if (!dims) {
|
|
53943
54030
|
writeJson({
|
|
53944
54031
|
ok: false,
|
|
53945
|
-
error: { code: "IMAGE_PROCESSING_ERROR", message: `Could not extract dimensions from ${
|
|
54032
|
+
error: { code: "IMAGE_PROCESSING_ERROR", message: `Could not extract dimensions from ${target4}` }
|
|
53946
54033
|
});
|
|
53947
54034
|
process.exit(1);
|
|
53948
54035
|
}
|
|
@@ -53950,8 +54037,8 @@ var dimensionsCommand = defineCommand147({
|
|
|
53950
54037
|
{
|
|
53951
54038
|
ok: true,
|
|
53952
54039
|
data: {
|
|
53953
|
-
target:
|
|
53954
|
-
source: isRemoteUrl(
|
|
54040
|
+
target: target4,
|
|
54041
|
+
source: isRemoteUrl(target4) ? "url" : "file",
|
|
53955
54042
|
width: dims.width,
|
|
53956
54043
|
height: dims.height,
|
|
53957
54044
|
aspectRatio: Math.round(dims.aspectRatio * 1e4) / 1e4,
|
|
@@ -54080,15 +54167,15 @@ registerSchema({
|
|
|
54080
54167
|
var ValidationError3 = class extends Error {
|
|
54081
54168
|
};
|
|
54082
54169
|
var UnusableTargetError = class extends Error {
|
|
54083
|
-
constructor(
|
|
54084
|
-
super(`"${
|
|
54085
|
-
this.target =
|
|
54170
|
+
constructor(target4) {
|
|
54171
|
+
super(`"${target4}" is neither an image URL nor a library image id.`);
|
|
54172
|
+
this.target = target4;
|
|
54086
54173
|
}
|
|
54087
54174
|
};
|
|
54088
54175
|
function readTargets(args5) {
|
|
54089
|
-
const
|
|
54176
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
54090
54177
|
const named = typeof args5.targets === "string" ? [args5.targets] : [];
|
|
54091
|
-
const all =
|
|
54178
|
+
const all = positionals2.length > 0 ? positionals2 : named;
|
|
54092
54179
|
const seen = /* @__PURE__ */ new Set();
|
|
54093
54180
|
const out = [];
|
|
54094
54181
|
for (const value of all) {
|
|
@@ -54113,13 +54200,13 @@ function classify(raw) {
|
|
|
54113
54200
|
}
|
|
54114
54201
|
return { raw, kind: "imageId" };
|
|
54115
54202
|
}
|
|
54116
|
-
async function resolveTarget(
|
|
54117
|
-
if (
|
|
54118
|
-
return { input:
|
|
54203
|
+
async function resolveTarget(target4) {
|
|
54204
|
+
if (target4.kind === "url") {
|
|
54205
|
+
return { input: target4.raw, url: target4.raw, baseName: baseNameFromUrl(target4.raw) };
|
|
54119
54206
|
}
|
|
54120
|
-
const doc = await apiGet("/api/images/get", { id:
|
|
54121
|
-
const stem = sanitizeBaseName(doc.name.length > 0 ? doc.name :
|
|
54122
|
-
return { input:
|
|
54207
|
+
const doc = await apiGet("/api/images/get", { id: target4.raw });
|
|
54208
|
+
const stem = sanitizeBaseName(doc.name.length > 0 ? doc.name : target4.raw);
|
|
54209
|
+
return { input: target4.raw, url: doc.imageUrl, baseName: stem };
|
|
54123
54210
|
}
|
|
54124
54211
|
async function fetchBytes(url) {
|
|
54125
54212
|
return await fetchExternalBytes(url, { maxBytes: MAX_REMOTE_IMAGE_BYTES });
|
|
@@ -54155,9 +54242,9 @@ function failureMessage(err, fallback) {
|
|
|
54155
54242
|
async function runDownloads(plan) {
|
|
54156
54243
|
const failed = [];
|
|
54157
54244
|
const fetched = [];
|
|
54158
|
-
for (const
|
|
54245
|
+
for (const target4 of plan.targets) {
|
|
54159
54246
|
try {
|
|
54160
|
-
const resolved = await resolveTarget(
|
|
54247
|
+
const resolved = await resolveTarget(target4);
|
|
54161
54248
|
const { buffer, contentType } = await fetchBytes(resolved.url);
|
|
54162
54249
|
fetched.push({
|
|
54163
54250
|
input: resolved.input,
|
|
@@ -54171,7 +54258,7 @@ async function runDownloads(plan) {
|
|
|
54171
54258
|
})
|
|
54172
54259
|
});
|
|
54173
54260
|
} catch (err) {
|
|
54174
|
-
failed.push({ input:
|
|
54261
|
+
failed.push({ input: target4.raw, error: failureMessage(err, "Download failed") });
|
|
54175
54262
|
}
|
|
54176
54263
|
}
|
|
54177
54264
|
const paths = disambiguate(fetched.map((item) => item.path));
|
|
@@ -54392,7 +54479,7 @@ function providerHitNormalizer(record, full) {
|
|
|
54392
54479
|
if (!full) {
|
|
54393
54480
|
return compact3;
|
|
54394
54481
|
}
|
|
54395
|
-
const
|
|
54482
|
+
const group2 = asRecord2(record.group);
|
|
54396
54483
|
return {
|
|
54397
54484
|
...compact3,
|
|
54398
54485
|
externalUrl: str(record.externalUrl),
|
|
@@ -54404,7 +54491,7 @@ function providerHitNormalizer(record, full) {
|
|
|
54404
54491
|
score: num(record.score),
|
|
54405
54492
|
deduped: typeof record.deduped === "boolean" ? record.deduped : void 0,
|
|
54406
54493
|
alsoInLibrary: str(record.alsoInLibrary),
|
|
54407
|
-
groupKey: str(
|
|
54494
|
+
groupKey: str(group2.key)
|
|
54408
54495
|
};
|
|
54409
54496
|
}
|
|
54410
54497
|
function readOutputFlags(args5) {
|
|
@@ -55742,18 +55829,18 @@ function findColorRangeInternal(data, ignoredColor = null, customThreshold) {
|
|
|
55742
55829
|
const color = { r: data[i], g: data[i + 1], b: data[i + 2] };
|
|
55743
55830
|
if (ignoredColor && colorDistance(color, ignoredColor) < threshold) continue;
|
|
55744
55831
|
let found = false;
|
|
55745
|
-
for (const
|
|
55746
|
-
const distance = colorDistance(
|
|
55747
|
-
const contrastRatio = getContrastRatio(
|
|
55832
|
+
for (const group2 of groups) {
|
|
55833
|
+
const distance = colorDistance(group2.color, color);
|
|
55834
|
+
const contrastRatio = getContrastRatio(group2.color, color);
|
|
55748
55835
|
let groupingThreshold = threshold;
|
|
55749
55836
|
if (contrastRatio > 3) groupingThreshold = Math.min(groupingThreshold, 8);
|
|
55750
|
-
const hueDistance = getHueDistance(
|
|
55837
|
+
const hueDistance = getHueDistance(group2.color, color);
|
|
55751
55838
|
if (hueDistance > 20) groupingThreshold = Math.min(groupingThreshold, 5);
|
|
55752
|
-
if (isHighlySaturated(color) && isHighlySaturated(
|
|
55839
|
+
if (isHighlySaturated(color) && isHighlySaturated(group2.color)) {
|
|
55753
55840
|
groupingThreshold = Math.min(groupingThreshold, 10);
|
|
55754
55841
|
}
|
|
55755
55842
|
if (distance < groupingThreshold) {
|
|
55756
|
-
|
|
55843
|
+
group2.count++;
|
|
55757
55844
|
found = true;
|
|
55758
55845
|
break;
|
|
55759
55846
|
}
|
|
@@ -55858,13 +55945,13 @@ function hasGradient(data) {
|
|
|
55858
55945
|
function perceivedLuminance(color) {
|
|
55859
55946
|
return (0.299 * color.r + 0.587 * color.g + 0.114 * color.b) / 255;
|
|
55860
55947
|
}
|
|
55861
|
-
function createSvgRecolorer(
|
|
55862
|
-
if (palette.length < 2) return () =>
|
|
55948
|
+
function createSvgRecolorer(target4, palette) {
|
|
55949
|
+
if (palette.length < 2) return () => target4;
|
|
55863
55950
|
const luminances = palette.map(perceivedLuminance);
|
|
55864
55951
|
const min = Math.min(...luminances);
|
|
55865
55952
|
const max = Math.max(...luminances);
|
|
55866
|
-
if (max - min < 0.05) return () =>
|
|
55867
|
-
const [h, s, targetLightness] = rgbToHsl(
|
|
55953
|
+
if (max - min < 0.05) return () => target4;
|
|
55954
|
+
const [h, s, targetLightness] = rgbToHsl(target4.r, target4.g, target4.b);
|
|
55868
55955
|
const lightnessRange = 0.75;
|
|
55869
55956
|
const minLightness = targetLightness >= 0.5 ? Math.max(0, targetLightness - lightnessRange) : targetLightness;
|
|
55870
55957
|
const maxLightness = targetLightness >= 0.5 ? targetLightness : Math.min(1, targetLightness + lightnessRange);
|
|
@@ -56858,18 +56945,18 @@ var uploadCommand = defineCommand167({
|
|
|
56858
56945
|
},
|
|
56859
56946
|
run: async ({ args: args5 }) => {
|
|
56860
56947
|
try {
|
|
56861
|
-
const
|
|
56862
|
-
if (!
|
|
56948
|
+
const target4 = args5.file;
|
|
56949
|
+
if (!target4) {
|
|
56863
56950
|
writeJson({
|
|
56864
56951
|
ok: false,
|
|
56865
56952
|
error: { code: "VALIDATION_ERROR", message: "File path or URL is required" }
|
|
56866
56953
|
});
|
|
56867
56954
|
process.exit(1);
|
|
56868
56955
|
}
|
|
56869
|
-
if (isRemoteUrl2(
|
|
56870
|
-
await uploadRemote(
|
|
56956
|
+
if (isRemoteUrl2(target4)) {
|
|
56957
|
+
await uploadRemote(target4, args5);
|
|
56871
56958
|
} else {
|
|
56872
|
-
await uploadLocal(
|
|
56959
|
+
await uploadLocal(target4, args5);
|
|
56873
56960
|
}
|
|
56874
56961
|
} catch (err) {
|
|
56875
56962
|
if (err instanceof ApiError) {
|
|
@@ -56881,7 +56968,7 @@ var uploadCommand = defineCommand167({
|
|
|
56881
56968
|
}
|
|
56882
56969
|
}
|
|
56883
56970
|
});
|
|
56884
|
-
async function uploadRemote(
|
|
56971
|
+
async function uploadRemote(target4, args5) {
|
|
56885
56972
|
const source = args5.source ?? "uploaded";
|
|
56886
56973
|
if (args5["dry-run"]) {
|
|
56887
56974
|
writeJson({
|
|
@@ -56889,7 +56976,7 @@ async function uploadRemote(target2, args5) {
|
|
|
56889
56976
|
dryRun: true,
|
|
56890
56977
|
operation: "images.upload (remote)",
|
|
56891
56978
|
params: {
|
|
56892
|
-
url:
|
|
56979
|
+
url: target4,
|
|
56893
56980
|
source,
|
|
56894
56981
|
externalId: args5["external-id"] ?? null,
|
|
56895
56982
|
externalUrl: args5["external-url"] ?? null,
|
|
@@ -56898,22 +56985,22 @@ async function uploadRemote(target2, args5) {
|
|
|
56898
56985
|
});
|
|
56899
56986
|
return;
|
|
56900
56987
|
}
|
|
56901
|
-
const body = { url:
|
|
56988
|
+
const body = { url: target4, source };
|
|
56902
56989
|
if (args5["external-id"]) body.externalId = args5["external-id"];
|
|
56903
56990
|
if (args5["external-url"]) body.externalUrl = args5["external-url"];
|
|
56904
56991
|
if (args5.context) body.descriptionContext = args5.context;
|
|
56905
56992
|
const data = await apiPost("/api/images/ingest", body);
|
|
56906
56993
|
writeJson({ ok: true, data });
|
|
56907
56994
|
}
|
|
56908
|
-
async function uploadLocal(
|
|
56909
|
-
const contentType = args5["content-type"] || detectImageContentType(
|
|
56995
|
+
async function uploadLocal(target4, args5) {
|
|
56996
|
+
const contentType = args5["content-type"] || detectImageContentType(target4);
|
|
56910
56997
|
if (args5["dry-run"]) {
|
|
56911
56998
|
writeJson({
|
|
56912
56999
|
ok: true,
|
|
56913
57000
|
dryRun: true,
|
|
56914
57001
|
operation: "images.upload (local)",
|
|
56915
57002
|
params: {
|
|
56916
|
-
file:
|
|
57003
|
+
file: target4,
|
|
56917
57004
|
contentType,
|
|
56918
57005
|
source: args5.source ?? null,
|
|
56919
57006
|
descriptionContext: args5.context ?? null
|
|
@@ -56922,7 +57009,7 @@ async function uploadLocal(target2, args5) {
|
|
|
56922
57009
|
return;
|
|
56923
57010
|
}
|
|
56924
57011
|
const data = await uploadLocalImage({
|
|
56925
|
-
file:
|
|
57012
|
+
file: target4,
|
|
56926
57013
|
contentType,
|
|
56927
57014
|
source: args5.source,
|
|
56928
57015
|
descriptionContext: args5.context
|
|
@@ -59211,7 +59298,7 @@ function classifyPreflightStatus(status) {
|
|
|
59211
59298
|
async function preflightProxyRoute(route, options = {}) {
|
|
59212
59299
|
if (route.kind !== "proxy") return { usable: true };
|
|
59213
59300
|
const timeoutMs = options.timeoutMs ?? 8e3;
|
|
59214
|
-
const
|
|
59301
|
+
const target4 = options.target ?? "example.com:443";
|
|
59215
59302
|
const endpoint = new URL(route.server);
|
|
59216
59303
|
const auth = Buffer.from(`${route.username}:${route.password}`).toString("base64");
|
|
59217
59304
|
return await new Promise((resolve5) => {
|
|
@@ -59223,8 +59310,8 @@ async function preflightProxyRoute(route, options = {}) {
|
|
|
59223
59310
|
host: endpoint.hostname,
|
|
59224
59311
|
port: Number(endpoint.port),
|
|
59225
59312
|
method: "CONNECT",
|
|
59226
|
-
path:
|
|
59227
|
-
headers: { "Proxy-Authorization": `Basic ${auth}`, Host:
|
|
59313
|
+
path: target4,
|
|
59314
|
+
headers: { "Proxy-Authorization": `Basic ${auth}`, Host: target4 },
|
|
59228
59315
|
timeout: timeoutMs
|
|
59229
59316
|
});
|
|
59230
59317
|
request.on("connect", (response, socket) => {
|
|
@@ -60150,9 +60237,9 @@ function bandsCollide(a, b, margin, maxGap) {
|
|
|
60150
60237
|
const gap = Math.min(Math.abs(shrunkA.bottom - shrunkB.top), Math.abs(shrunkB.bottom - shrunkA.top));
|
|
60151
60238
|
return gap <= maxGap;
|
|
60152
60239
|
}
|
|
60153
|
-
function shouldPromoteToParent(
|
|
60154
|
-
const isRunt =
|
|
60155
|
-
return isRunt &&
|
|
60240
|
+
function shouldPromoteToParent(group2) {
|
|
60241
|
+
const isRunt = group2.childCount < 3 || group2.height < 80;
|
|
60242
|
+
return isRunt && group2.parentHeight < 1600;
|
|
60156
60243
|
}
|
|
60157
60244
|
|
|
60158
60245
|
// src/engine/landing-library/segment.ts
|
|
@@ -60371,35 +60458,35 @@ var inPageSegment = (options) => {
|
|
|
60371
60458
|
};
|
|
60372
60459
|
const clusterOnce = (groups2) => {
|
|
60373
60460
|
const buckets = [];
|
|
60374
|
-
for (const
|
|
60375
|
-
if (
|
|
60376
|
-
buckets.push([
|
|
60461
|
+
for (const group2 of groups2) {
|
|
60462
|
+
if (group2.sealed) {
|
|
60463
|
+
buckets.push([group2]);
|
|
60377
60464
|
continue;
|
|
60378
60465
|
}
|
|
60379
|
-
const
|
|
60466
|
+
const target4 = buckets.find(
|
|
60380
60467
|
(bucket) => bucket.some(
|
|
60381
60468
|
(member) => !member.sealed && geom.bandsCollide(
|
|
60382
60469
|
{ top: member.top, bottom: member.bottom },
|
|
60383
|
-
{ top:
|
|
60470
|
+
{ top: group2.top, bottom: group2.bottom },
|
|
60384
60471
|
options.collisionMargin,
|
|
60385
60472
|
gapThreshold
|
|
60386
60473
|
)
|
|
60387
60474
|
)
|
|
60388
60475
|
);
|
|
60389
|
-
if (
|
|
60390
|
-
else buckets.push([
|
|
60476
|
+
if (target4) target4.push(group2);
|
|
60477
|
+
else buckets.push([group2]);
|
|
60391
60478
|
}
|
|
60392
60479
|
if (buckets.length === groups2.length) return groups2;
|
|
60393
60480
|
return buckets.flatMap((bucket) => bucket.length === 1 ? [bucket[0]] : mergeBucket(bucket));
|
|
60394
60481
|
};
|
|
60395
|
-
let groups = leaves.map((
|
|
60396
|
-
root:
|
|
60397
|
-
top:
|
|
60398
|
-
bottom:
|
|
60399
|
-
left:
|
|
60400
|
-
right:
|
|
60401
|
-
height:
|
|
60402
|
-
leaves: [
|
|
60482
|
+
let groups = leaves.map((leaf2) => ({
|
|
60483
|
+
root: leaf2.element,
|
|
60484
|
+
top: leaf2.top,
|
|
60485
|
+
bottom: leaf2.bottom,
|
|
60486
|
+
left: leaf2.left,
|
|
60487
|
+
right: leaf2.right,
|
|
60488
|
+
height: leaf2.height,
|
|
60489
|
+
leaves: [leaf2],
|
|
60403
60490
|
sealed: false
|
|
60404
60491
|
}));
|
|
60405
60492
|
for (let pass = 0; pass < 40; pass++) {
|
|
@@ -60409,21 +60496,21 @@ var inPageSegment = (options) => {
|
|
|
60409
60496
|
}
|
|
60410
60497
|
for (let pass = 0; pass < 10; pass++) {
|
|
60411
60498
|
let promoted = false;
|
|
60412
|
-
groups = groups.map((
|
|
60413
|
-
const parent =
|
|
60414
|
-
if (!parent || parent === document.documentElement || parent === document.body) return
|
|
60499
|
+
groups = groups.map((group2) => {
|
|
60500
|
+
const parent = group2.root.parentElement;
|
|
60501
|
+
if (!parent || parent === document.documentElement || parent === document.body) return group2;
|
|
60415
60502
|
const parentBox = boxOf(parent);
|
|
60416
|
-
if (!parentBox) return
|
|
60503
|
+
if (!parentBox) return group2;
|
|
60417
60504
|
if (!geom.shouldPromoteToParent({
|
|
60418
|
-
childCount:
|
|
60419
|
-
height:
|
|
60505
|
+
childCount: group2.leaves.length,
|
|
60506
|
+
height: group2.height,
|
|
60420
60507
|
parentHeight: parentBox.height
|
|
60421
60508
|
})) {
|
|
60422
|
-
return
|
|
60509
|
+
return group2;
|
|
60423
60510
|
}
|
|
60424
60511
|
promoted = true;
|
|
60425
60512
|
return {
|
|
60426
|
-
...
|
|
60513
|
+
...group2,
|
|
60427
60514
|
root: parent,
|
|
60428
60515
|
top: parentBox.top,
|
|
60429
60516
|
bottom: parentBox.bottom,
|
|
@@ -60439,23 +60526,23 @@ var inPageSegment = (options) => {
|
|
|
60439
60526
|
const containsBox = (outer, inner) => outer.top - 4 <= inner.top && outer.bottom + 4 >= inner.bottom && outer.left - 4 <= inner.left && outer.right + 4 >= inner.right;
|
|
60440
60527
|
const deduped = [];
|
|
60441
60528
|
const area = (g) => (g.right - g.left) * g.height;
|
|
60442
|
-
for (const
|
|
60529
|
+
for (const group2 of groups.slice().sort((a, b) => area(b) - area(a) || b.leaves.length - a.leaves.length)) {
|
|
60443
60530
|
const duplicate = deduped.some(
|
|
60444
|
-
(kept) => kept.root ===
|
|
60531
|
+
(kept) => kept.root === group2.root || kept.root.contains(group2.root) || sameBox(kept, group2) || containsBox(kept, group2)
|
|
60445
60532
|
);
|
|
60446
|
-
if (!duplicate) deduped.push(
|
|
60533
|
+
if (!duplicate) deduped.push(group2);
|
|
60447
60534
|
}
|
|
60448
|
-
return deduped.filter((
|
|
60535
|
+
return deduped.filter((group2) => group2.height > 0 && group2.right - group2.left > 0).sort((a, b) => a.top - b.top).map((group2, index) => ({
|
|
60449
60536
|
index,
|
|
60450
|
-
selector: selectorFor(
|
|
60537
|
+
selector: selectorFor(group2.root),
|
|
60451
60538
|
rect: {
|
|
60452
|
-
top:
|
|
60453
|
-
left:
|
|
60454
|
-
width:
|
|
60455
|
-
height:
|
|
60539
|
+
top: group2.top,
|
|
60540
|
+
left: group2.left,
|
|
60541
|
+
width: group2.right - group2.left,
|
|
60542
|
+
height: group2.height
|
|
60456
60543
|
},
|
|
60457
|
-
leafCount:
|
|
60458
|
-
textPreview: visibleText(
|
|
60544
|
+
leafCount: group2.leaves.length,
|
|
60545
|
+
textPreview: visibleText(group2.root).slice(0, 200)
|
|
60459
60546
|
}));
|
|
60460
60547
|
};
|
|
60461
60548
|
|
|
@@ -60482,8 +60569,8 @@ async function captureMotionTake(browser, url, selector, timeoutMs = 45e3) {
|
|
|
60482
60569
|
await settleNavigation(page);
|
|
60483
60570
|
await page.waitForLoadState("networkidle", { timeout: 8e3 }).catch(() => void 0);
|
|
60484
60571
|
await settleConsent(page);
|
|
60485
|
-
const
|
|
60486
|
-
if (!await
|
|
60572
|
+
const target4 = page.locator(selector).first();
|
|
60573
|
+
if (!await target4.count().catch(() => 0)) return null;
|
|
60487
60574
|
await page.evaluate((sectionSelector) => {
|
|
60488
60575
|
const element = document.querySelector(sectionSelector);
|
|
60489
60576
|
if (!element) return;
|
|
@@ -60537,12 +60624,12 @@ async function aimAtSection(page, selector) {
|
|
|
60537
60624
|
}
|
|
60538
60625
|
async function hideFloatingFurniture(page, selector) {
|
|
60539
60626
|
await page.evaluate((sectionSelector) => {
|
|
60540
|
-
const
|
|
60541
|
-
if (!
|
|
60627
|
+
const target4 = document.querySelector(sectionSelector);
|
|
60628
|
+
if (!target4) return;
|
|
60542
60629
|
for (const element of Array.from(document.querySelectorAll("*"))) {
|
|
60543
60630
|
const position = getComputedStyle(element).position;
|
|
60544
60631
|
if (position !== "fixed" && position !== "sticky") continue;
|
|
60545
|
-
if (element.contains(
|
|
60632
|
+
if (element.contains(target4) || target4.contains(element) || element === target4) continue;
|
|
60546
60633
|
element.style.setProperty("visibility", "hidden", "important");
|
|
60547
60634
|
}
|
|
60548
60635
|
}, selector);
|
|
@@ -60599,9 +60686,9 @@ async function renderBundleToPng(browser, html, viewportWidth, options = {}) {
|
|
|
60599
60686
|
await page.waitForTimeout(300);
|
|
60600
60687
|
if (!wholePage) {
|
|
60601
60688
|
for (const selector of [`[${SECTION_ROOT_ATTRIBUTE}]`, "body > *"]) {
|
|
60602
|
-
const
|
|
60603
|
-
if (!await
|
|
60604
|
-
const shot = await
|
|
60689
|
+
const target4 = page.locator(selector).first();
|
|
60690
|
+
if (!await target4.count()) continue;
|
|
60691
|
+
const shot = await target4.screenshot({ type: "png", timeout: timeoutMs }).catch(() => null);
|
|
60605
60692
|
if (shot) return shot;
|
|
60606
60693
|
}
|
|
60607
60694
|
}
|
|
@@ -61077,8 +61164,8 @@ async function scrapeLanding(options) {
|
|
|
61077
61164
|
import { existsSync as existsSync9 } from "fs";
|
|
61078
61165
|
import path41 from "path";
|
|
61079
61166
|
var SCRATCH_DIR = ".baker";
|
|
61080
|
-
function isWithin(parent,
|
|
61081
|
-
const relative = path41.relative(parent,
|
|
61167
|
+
function isWithin(parent, target4) {
|
|
61168
|
+
const relative = path41.relative(parent, target4);
|
|
61082
61169
|
return relative === "" || !relative.startsWith("..") && !path41.isAbsolute(relative);
|
|
61083
61170
|
}
|
|
61084
61171
|
function findRepoRoot(from) {
|
|
@@ -61369,8 +61456,8 @@ registerSchema({
|
|
|
61369
61456
|
function buildSearchBody(args5) {
|
|
61370
61457
|
const body = {};
|
|
61371
61458
|
const setList2 = (key, value) => {
|
|
61372
|
-
const
|
|
61373
|
-
if (
|
|
61459
|
+
const list3 = splitList2(value);
|
|
61460
|
+
if (list3) Object.assign(body, { [key]: list3 });
|
|
61374
61461
|
};
|
|
61375
61462
|
if (args5.query) body.query = String(args5.query);
|
|
61376
61463
|
if (args5["similar-to"]) body.similarToSectionId = String(args5["similar-to"]);
|
|
@@ -62145,9 +62232,9 @@ function customEntry(server) {
|
|
|
62145
62232
|
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.";
|
|
62146
62233
|
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.";
|
|
62147
62234
|
function parseHeaders(raw, rawArgs) {
|
|
62148
|
-
const
|
|
62235
|
+
const list3 = repeatedValues(rawArgs, "header", raw);
|
|
62149
62236
|
const headers = {};
|
|
62150
|
-
for (const entry of
|
|
62237
|
+
for (const entry of list3) {
|
|
62151
62238
|
const text2 = String(entry);
|
|
62152
62239
|
const sep = text2.indexOf(":") >= 0 && (text2.indexOf(":") < text2.indexOf("=") || text2.indexOf("=") < 0) ? ":" : "=";
|
|
62153
62240
|
const at = text2.indexOf(sep);
|
|
@@ -63316,7 +63403,7 @@ Examples:
|
|
|
63316
63403
|
"no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
|
|
63317
63404
|
},
|
|
63318
63405
|
run: async ({ args: args5 }) => {
|
|
63319
|
-
const
|
|
63406
|
+
const target4 = args5.target;
|
|
63320
63407
|
const location2 = args5.location || void 0;
|
|
63321
63408
|
const language = args5.language || void 0;
|
|
63322
63409
|
const sort = args5.sort || void 0;
|
|
@@ -63326,7 +63413,7 @@ Examples:
|
|
|
63326
63413
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63327
63414
|
try {
|
|
63328
63415
|
const data = await apiPost("/api/research/keywords-for-site", {
|
|
63329
|
-
target:
|
|
63416
|
+
target: target4,
|
|
63330
63417
|
location: location2,
|
|
63331
63418
|
language,
|
|
63332
63419
|
sort,
|
|
@@ -63499,7 +63586,7 @@ Examples:
|
|
|
63499
63586
|
"no-cache": { type: "boolean", description: "Skip server cache, hit API directly", required: false }
|
|
63500
63587
|
},
|
|
63501
63588
|
run: async ({ args: args5 }) => {
|
|
63502
|
-
const
|
|
63589
|
+
const target4 = args5.target;
|
|
63503
63590
|
const location2 = args5.location || void 0;
|
|
63504
63591
|
const language = args5.language || void 0;
|
|
63505
63592
|
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
@@ -63507,7 +63594,7 @@ Examples:
|
|
|
63507
63594
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63508
63595
|
try {
|
|
63509
63596
|
const data = await apiPost("/api/research/relevant-pages", {
|
|
63510
|
-
target:
|
|
63597
|
+
target: target4,
|
|
63511
63598
|
location: location2,
|
|
63512
63599
|
language,
|
|
63513
63600
|
limit: limit2,
|
|
@@ -63854,7 +63941,7 @@ function refuseMisusedKinds(kind, args5) {
|
|
|
63854
63941
|
}
|
|
63855
63942
|
}
|
|
63856
63943
|
function refuseStrayFlags(kind, args5) {
|
|
63857
|
-
const allowed = new Set(TRIGGER_TARGETS[kind].map((
|
|
63944
|
+
const allowed = new Set(TRIGGER_TARGETS[kind].map((target4) => TRIGGER_TARGET_FIELDS[target4.field].flag));
|
|
63858
63945
|
const stray = TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag).filter(
|
|
63859
63946
|
(flag3) => !allowed.has(flag3) && flagText(args5, flag3) !== void 0 && !(kind === "experiment.started" && flag3 === "experiment")
|
|
63860
63947
|
);
|
|
@@ -64090,13 +64177,13 @@ var createCommand3 = defineCommand197({
|
|
|
64090
64177
|
try {
|
|
64091
64178
|
refuseAutoPublish(args5);
|
|
64092
64179
|
const name = args5.name;
|
|
64093
|
-
const
|
|
64180
|
+
const description2 = args5.description;
|
|
64094
64181
|
const prompt = args5.prompt;
|
|
64095
64182
|
const template = typeof args5.template === "string" ? args5.template.trim() : "";
|
|
64096
64183
|
if (template.length === 0 && (!name || name.trim().length === 0)) {
|
|
64097
64184
|
failValidation4("--name is required. Or pass --template to use a recipe's name.");
|
|
64098
64185
|
}
|
|
64099
|
-
if (template.length === 0 && (!
|
|
64186
|
+
if (template.length === 0 && (!description2 || description2.trim().length === 0)) {
|
|
64100
64187
|
failValidation4("--description is required. Or pass --template to use a recipe's line.");
|
|
64101
64188
|
}
|
|
64102
64189
|
if (template.length === 0 && (!prompt || prompt.trim().length === 0)) {
|
|
@@ -64107,7 +64194,7 @@ var createCommand3 = defineCommand197({
|
|
|
64107
64194
|
const body = {
|
|
64108
64195
|
chatId: requireChatId(),
|
|
64109
64196
|
...name?.trim() ? { name } : {},
|
|
64110
|
-
...
|
|
64197
|
+
...description2?.trim() ? { description: description2 } : {},
|
|
64111
64198
|
enabled: !args5.disabled,
|
|
64112
64199
|
...trigger,
|
|
64113
64200
|
...prompt ? { prompt } : {},
|
|
@@ -64456,8 +64543,8 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64456
64543
|
try {
|
|
64457
64544
|
const save = flag3("save");
|
|
64458
64545
|
const publish = flag3("publish");
|
|
64459
|
-
const
|
|
64460
|
-
if ([save, publish,
|
|
64546
|
+
const remove2 = flag3("delete");
|
|
64547
|
+
if ([save, publish, remove2].filter((id) => id.length > 0).length > 1) {
|
|
64461
64548
|
failValidation4("Pass one of --save, --publish or --delete at a time.");
|
|
64462
64549
|
}
|
|
64463
64550
|
if (save.length > 0) {
|
|
@@ -64486,10 +64573,10 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64486
64573
|
writeJson(response2);
|
|
64487
64574
|
return;
|
|
64488
64575
|
}
|
|
64489
|
-
if (
|
|
64576
|
+
if (remove2.length > 0) {
|
|
64490
64577
|
const response2 = await apiPost("/api/marketplace/remove", {
|
|
64491
64578
|
chatId: requireChatId(),
|
|
64492
|
-
slug:
|
|
64579
|
+
slug: remove2
|
|
64493
64580
|
});
|
|
64494
64581
|
writeJson(response2);
|
|
64495
64582
|
return;
|
|
@@ -64787,7 +64874,7 @@ var schemaCommand2 = defineCommand208({
|
|
|
64787
64874
|
});
|
|
64788
64875
|
|
|
64789
64876
|
// src/commands/shopify/index.ts
|
|
64790
|
-
import { defineCommand as
|
|
64877
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
64791
64878
|
|
|
64792
64879
|
// src/commands/shopify/buyers.ts
|
|
64793
64880
|
import { defineCommand as defineCommand209 } from "citty";
|
|
@@ -65074,7 +65161,18 @@ var shopifyStoreSummarySchema = z50.object({
|
|
|
65074
65161
|
});
|
|
65075
65162
|
var shopifyStoreResponseSchema = z50.object({
|
|
65076
65163
|
store: shopifyStoreStateSchema,
|
|
65077
|
-
summary: shopifyStoreSummarySchema
|
|
65164
|
+
summary: shopifyStoreSummarySchema,
|
|
65165
|
+
/**
|
|
65166
|
+
* Which store changes Baker may make (S9), by what the store allowed: false
|
|
65167
|
+
* means `baker shopify change …` will ask the user to allow it first.
|
|
65168
|
+
*/
|
|
65169
|
+
canChange: z50.object({
|
|
65170
|
+
products: z50.boolean(),
|
|
65171
|
+
publishing: z50.boolean(),
|
|
65172
|
+
discounts: z50.boolean(),
|
|
65173
|
+
redirects: z50.boolean(),
|
|
65174
|
+
marketing: z50.boolean()
|
|
65175
|
+
}).optional()
|
|
65078
65176
|
});
|
|
65079
65177
|
var shopifyProductRowSchema = z50.object({
|
|
65080
65178
|
productId: z50.string(),
|
|
@@ -65112,7 +65210,7 @@ var shopifyVariantSchema = z50.object({
|
|
|
65112
65210
|
compareAtPrice: shopifyPriceSchema.optional(),
|
|
65113
65211
|
stock: shopifyOptionStockSchema,
|
|
65114
65212
|
quantity: z50.number().optional(),
|
|
65115
|
-
/** The link for
|
|
65213
|
+
/** The option's buy link for ads, emails and messages (a landing places `<ShopifyProduct>` instead): never build a Shopify link by hand. Absent when the option can't be bought. */
|
|
65116
65214
|
buyUrl: z50.string().optional(),
|
|
65117
65215
|
buyUrlKind: shopifyBuyDestinationSchema.optional(),
|
|
65118
65216
|
/** Why there is no buy link. */
|
|
@@ -65227,7 +65325,7 @@ var shopifyProductDetailSchema = z50.object({
|
|
|
65227
65325
|
handle: z50.string(),
|
|
65228
65326
|
/** The product's page in Baker — the link to share with the user. */
|
|
65229
65327
|
url: z50.string(),
|
|
65230
|
-
/** The product's page on the online store: to look at, never a buy button's link (that is each option's `buyUrl
|
|
65328
|
+
/** The product's page on the online store: to look at, never a buy button's link (that is each option's `buyUrl`, or `<ShopifyProduct>` on a landing). */
|
|
65231
65329
|
storeUrl: z50.string().optional(),
|
|
65232
65330
|
availability: shopifyAvailabilitySchema.optional(),
|
|
65233
65331
|
status: shopifyProductStatusSchema.optional(),
|
|
@@ -65791,6 +65889,359 @@ var shopifyCohortsResponseSchema = z51.object({
|
|
|
65791
65889
|
cohorts: z51.array(shopifyCohortSchema)
|
|
65792
65890
|
});
|
|
65793
65891
|
|
|
65892
|
+
// ../api/src/shopify/writes.ts
|
|
65893
|
+
import { z as z52 } from "zod";
|
|
65894
|
+
var SHOPIFY_TEMP_REF_PREFIX = "shopify_temp_";
|
|
65895
|
+
var SHOPIFY_PERMISSION_NEEDED_PREFIX = "Baker isn't allowed to change this Shopify store yet";
|
|
65896
|
+
var shopifyWriteEntitySchema = z52.enum([
|
|
65897
|
+
"product",
|
|
65898
|
+
"variant",
|
|
65899
|
+
"metafield",
|
|
65900
|
+
"collection",
|
|
65901
|
+
"discountCode",
|
|
65902
|
+
"urlRedirect",
|
|
65903
|
+
"marketingActivity",
|
|
65904
|
+
"webPixel",
|
|
65905
|
+
"signupOffer"
|
|
65906
|
+
]);
|
|
65907
|
+
var shopifyDraftOpKindSchema = z52.enum([
|
|
65908
|
+
"shopify.product.update",
|
|
65909
|
+
"shopify.variant.update",
|
|
65910
|
+
"shopify.metafield.set",
|
|
65911
|
+
"shopify.metafield.delete",
|
|
65912
|
+
"shopify.collection.create",
|
|
65913
|
+
"shopify.collection.publish",
|
|
65914
|
+
"shopify.collection.unpublish",
|
|
65915
|
+
"shopify.collection.update",
|
|
65916
|
+
"shopify.collection.delete",
|
|
65917
|
+
"shopify.collection.addProducts",
|
|
65918
|
+
"shopify.collection.removeProducts",
|
|
65919
|
+
"shopify.discountCode.create",
|
|
65920
|
+
"shopify.discountCode.deactivate",
|
|
65921
|
+
"shopify.discountCode.schedule",
|
|
65922
|
+
"shopify.urlRedirect.create",
|
|
65923
|
+
"shopify.urlRedirect.delete",
|
|
65924
|
+
"shopify.marketingActivity.upsert",
|
|
65925
|
+
"shopify.marketingActivity.delete",
|
|
65926
|
+
"shopify.webPixel.update",
|
|
65927
|
+
"shopify.signupOffer.set",
|
|
65928
|
+
"shopify.signupOffer.end"
|
|
65929
|
+
]);
|
|
65930
|
+
var shopifyDecimalSchema = z52.string().regex(/^\d{1,12}(\.\d{1,4})?$/, 'write amounts as a decimal string, e.g. "19.95"');
|
|
65931
|
+
var tagSchema = z52.string().trim().min(1).max(255);
|
|
65932
|
+
var seoSchema = z52.object({ title: z52.string().max(255).optional(), description: z52.string().max(320).optional() }).strict();
|
|
65933
|
+
var SHOPIFY_DESCRIPTION_MAX_CHARS = 2e5;
|
|
65934
|
+
var descriptionHtmlSchema = z52.string().max(SHOPIFY_DESCRIPTION_MAX_CHARS);
|
|
65935
|
+
var productUpdateSchema = z52.object({
|
|
65936
|
+
title: z52.string().trim().min(1).max(255).optional(),
|
|
65937
|
+
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
65938
|
+
seo: seoSchema.optional(),
|
|
65939
|
+
/** The WHOLE tag list after the change (Shopify replaces it). `addTags`/`removeTags` are resolved against the live tags. */
|
|
65940
|
+
tags: z52.array(tagSchema).max(250).optional(),
|
|
65941
|
+
addTags: z52.array(tagSchema).max(250).optional(),
|
|
65942
|
+
removeTags: z52.array(tagSchema).max(250).optional(),
|
|
65943
|
+
productType: z52.string().max(255).optional()
|
|
65944
|
+
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change").refine(
|
|
65945
|
+
(payload) => payload.tags === void 0 || payload.addTags === void 0 && payload.removeTags === void 0,
|
|
65946
|
+
"give either the whole `tags` list or `addTags`/`removeTags`, not both"
|
|
65947
|
+
);
|
|
65948
|
+
var shopifyWeightUnitSchema = z52.enum(["GRAMS", "KILOGRAMS", "OUNCES", "POUNDS"]);
|
|
65949
|
+
var variantUpdateSchema = z52.object({
|
|
65950
|
+
barcode: z52.string().trim().max(255).optional(),
|
|
65951
|
+
sku: z52.string().trim().max(255).optional(),
|
|
65952
|
+
weight: z52.object({ value: z52.number().nonnegative(), unit: shopifyWeightUnitSchema }).strict().optional(),
|
|
65953
|
+
price: shopifyDecimalSchema.optional(),
|
|
65954
|
+
/** `null` clears the sale ("compare at") price. */
|
|
65955
|
+
compareAtPrice: shopifyDecimalSchema.nullable().optional()
|
|
65956
|
+
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change");
|
|
65957
|
+
var metafieldKeySchema = z52.string().min(2).max(64).regex(/^[A-Za-z0-9_-]+$/, "letters, digits, `_` and `-` only");
|
|
65958
|
+
var metafieldNamespaceSchema = z52.string().min(2).max(255).regex(/^[A-Za-z0-9_-]+$/, "letters, digits, `_` and `-` only");
|
|
65959
|
+
var metafieldSetSchema = z52.object({
|
|
65960
|
+
namespace: metafieldNamespaceSchema,
|
|
65961
|
+
key: metafieldKeySchema,
|
|
65962
|
+
/** Shopify's metafield type, e.g. `single_line_text_field`, `multi_line_text_field`, `rich_text_field`, `number_integer`, `boolean`, `json`. */
|
|
65963
|
+
type: z52.string().min(1).max(100),
|
|
65964
|
+
value: z52.string().max(1e5)
|
|
65965
|
+
}).strict();
|
|
65966
|
+
var metafieldDeleteSchema = z52.object({ namespace: metafieldNamespaceSchema, key: metafieldKeySchema }).strict();
|
|
65967
|
+
var shopifyCollectionSortOrderSchema = z52.enum([
|
|
65968
|
+
"MANUAL",
|
|
65969
|
+
"BEST_SELLING",
|
|
65970
|
+
"ALPHA_ASC",
|
|
65971
|
+
"ALPHA_DESC",
|
|
65972
|
+
"PRICE_DESC",
|
|
65973
|
+
"PRICE_ASC",
|
|
65974
|
+
"CREATED",
|
|
65975
|
+
"CREATED_DESC"
|
|
65976
|
+
]);
|
|
65977
|
+
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");
|
|
65978
|
+
var SHOPIFY_COLLECTION_PRODUCTS_MAX = 250;
|
|
65979
|
+
var collectionCreateSchema = z52.object({
|
|
65980
|
+
title: z52.string().trim().min(1).max(255),
|
|
65981
|
+
handle: handleSchema.optional(),
|
|
65982
|
+
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
65983
|
+
seo: seoSchema.optional(),
|
|
65984
|
+
sortOrder: shopifyCollectionSortOrderSchema.optional(),
|
|
65985
|
+
/** The theme template the collection page uses (the part after `collection.`). Kept when a deleted collection is put back. */
|
|
65986
|
+
templateSuffix: z52.string().max(255).optional(),
|
|
65987
|
+
/** Product ids, handles or links, in the order shown with sort order MANUAL. */
|
|
65988
|
+
products: z52.array(z52.string().min(1)).max(SHOPIFY_COLLECTION_PRODUCTS_MAX).optional(),
|
|
65989
|
+
/** Show it on the online store (a second change, staged with it). Default true. */
|
|
65990
|
+
onlineStore: z52.boolean().optional()
|
|
65991
|
+
}).strict();
|
|
65992
|
+
var collectionUpdateSchema = z52.object({
|
|
65993
|
+
title: z52.string().trim().min(1).max(255).optional(),
|
|
65994
|
+
descriptionHtml: descriptionHtmlSchema.optional(),
|
|
65995
|
+
seo: seoSchema.optional(),
|
|
65996
|
+
sortOrder: shopifyCollectionSortOrderSchema.optional()
|
|
65997
|
+
}).strict().refine((payload) => Object.keys(payload).length > 0, "name at least one thing to change");
|
|
65998
|
+
var collectionProductsSchema = z52.object({ products: z52.array(z52.string().min(1)).min(1).max(SHOPIFY_COLLECTION_PRODUCTS_MAX) }).strict();
|
|
65999
|
+
var isoDateTimeSchema = z52.iso.datetime({ offset: true });
|
|
66000
|
+
var discountCodeSchema = z52.string().regex(/^[A-Za-z0-9_-]{3,64}$/, "3\u201364 letters, digits, `_` or `-`, e.g. SPRING10");
|
|
66001
|
+
var discountValueSchema = z52.union([
|
|
66002
|
+
z52.object({ percentage: z52.number().min(1).max(100) }).strict(),
|
|
66003
|
+
z52.object({ amount: shopifyDecimalSchema }).strict()
|
|
66004
|
+
]);
|
|
66005
|
+
var discountAppliesToSchema = z52.union([
|
|
66006
|
+
z52.object({ all: z52.literal(true) }).strict(),
|
|
66007
|
+
z52.object({ products: z52.array(z52.string().min(1)).min(1).max(100) }).strict(),
|
|
66008
|
+
z52.object({ collections: z52.array(z52.string().min(1)).min(1).max(100) }).strict()
|
|
66009
|
+
]);
|
|
66010
|
+
var discountCreateSchema = z52.object({
|
|
66011
|
+
code: discountCodeSchema,
|
|
66012
|
+
/** What the store's staff see; defaults to the code. */
|
|
66013
|
+
title: z52.string().trim().min(1).max(255).optional(),
|
|
66014
|
+
value: discountValueSchema,
|
|
66015
|
+
appliesTo: discountAppliesToSchema,
|
|
66016
|
+
minimumSubtotal: shopifyDecimalSchema.optional(),
|
|
66017
|
+
minimumQuantity: z52.number().int().min(1).max(1e4).optional(),
|
|
66018
|
+
/** Default: the moment it is published. */
|
|
66019
|
+
startsAt: isoDateTimeSchema.optional(),
|
|
66020
|
+
endsAt: isoDateTimeSchema.optional(),
|
|
66021
|
+
usageLimit: z52.number().int().min(1).max(1e6).optional(),
|
|
66022
|
+
/** Default true. */
|
|
66023
|
+
oncePerCustomer: z52.boolean().optional(),
|
|
66024
|
+
combinesWith: z52.object({
|
|
66025
|
+
productDiscounts: z52.boolean().optional(),
|
|
66026
|
+
orderDiscounts: z52.boolean().optional(),
|
|
66027
|
+
shippingDiscounts: z52.boolean().optional()
|
|
66028
|
+
}).strict().optional()
|
|
66029
|
+
}).strict().refine(
|
|
66030
|
+
(payload) => payload.minimumSubtotal === void 0 || payload.minimumQuantity === void 0,
|
|
66031
|
+
"a discount takes a minimum amount or a minimum quantity, not both"
|
|
66032
|
+
);
|
|
66033
|
+
var discountScheduleSchema = z52.object({ startsAt: isoDateTimeSchema, endsAt: isoDateTimeSchema.nullable() }).strict();
|
|
66034
|
+
var storePathSchema = z52.string().min(2).max(1024).regex(/^\/[^\s]*$/, 'a path on the store starting with "/", e.g. /collections/old');
|
|
66035
|
+
var urlRedirectCreateSchema = z52.object({
|
|
66036
|
+
from: storePathSchema,
|
|
66037
|
+
to: z52.union([storePathSchema, z52.url({ protocol: /^https$/ })])
|
|
66038
|
+
}).strict();
|
|
66039
|
+
var shopifyMarketingPlatformSchema = z52.enum(["google-ads", "meta"]);
|
|
66040
|
+
var marketingUpsertSchema = z52.object({
|
|
66041
|
+
platform: shopifyMarketingPlatformSchema,
|
|
66042
|
+
accountId: z52.string().min(1).max(64),
|
|
66043
|
+
campaignId: z52.string().regex(/^\d+$/, "the campaign's numeric id"),
|
|
66044
|
+
utm: z52.object({
|
|
66045
|
+
campaign: z52.string().trim().min(1).max(255),
|
|
66046
|
+
source: z52.string().trim().min(1).max(255),
|
|
66047
|
+
medium: z52.string().trim().min(1).max(255)
|
|
66048
|
+
}).strict()
|
|
66049
|
+
}).strict();
|
|
66050
|
+
var signupOfferHandleSchema = z52.string().regex(/^[a-z0-9][a-z0-9-]{1,39}$/, "2\u201340 lowercase letters, digits and dashes, e.g. welcome-10");
|
|
66051
|
+
var signupOfferSetSchema = z52.object({
|
|
66052
|
+
/** What the store's staff see in front of each code, and the Store page's row. */
|
|
66053
|
+
name: z52.string().trim().min(1).max(80),
|
|
66054
|
+
value: discountValueSchema,
|
|
66055
|
+
appliesTo: discountAppliesToSchema,
|
|
66056
|
+
minimumSubtotal: shopifyDecimalSchema.optional(),
|
|
66057
|
+
/** Each code's life, from the moment it is given. */
|
|
66058
|
+
validForDays: z52.number().int().min(1).max(365),
|
|
66059
|
+
/** The offer stops giving codes after this; no code outlives it. */
|
|
66060
|
+
endsAt: isoDateTimeSchema.optional(),
|
|
66061
|
+
/** How many codes the offer gives in all. */
|
|
66062
|
+
maxCodes: z52.number().int().min(1).max(1e5).optional(),
|
|
66063
|
+
/** The start of every code (WELCOME-7Q2M9XKD); default: the handle in capitals. */
|
|
66064
|
+
codePrefix: z52.string().regex(/^[A-Z0-9]{2,12}$/, "2\u201312 capital letters or digits, e.g. WELCOME").optional(),
|
|
66065
|
+
combinesWith: z52.object({
|
|
66066
|
+
productDiscounts: z52.boolean().optional(),
|
|
66067
|
+
orderDiscounts: z52.boolean().optional(),
|
|
66068
|
+
shippingDiscounts: z52.boolean().optional()
|
|
66069
|
+
}).strict().optional()
|
|
66070
|
+
}).strict();
|
|
66071
|
+
var emptySchema = z52.object({}).strict();
|
|
66072
|
+
var opFields = {
|
|
66073
|
+
/** Optional caller-chosen ref for a create, so later ops in the batch can name it (`shopify_temp_…`). */
|
|
66074
|
+
ref: z52.string().startsWith(SHOPIFY_TEMP_REF_PREFIX).max(80).optional()
|
|
66075
|
+
};
|
|
66076
|
+
var target2 = z52.string().trim().min(1).max(2048);
|
|
66077
|
+
var shopifyDraftOpInputSchema = z52.discriminatedUnion("kind", [
|
|
66078
|
+
z52.object({ kind: z52.literal("shopify.product.update"), target: target2, payload: productUpdateSchema, ...opFields }),
|
|
66079
|
+
z52.object({ kind: z52.literal("shopify.variant.update"), target: target2, payload: variantUpdateSchema, ...opFields }),
|
|
66080
|
+
z52.object({ kind: z52.literal("shopify.metafield.set"), target: target2, payload: metafieldSetSchema, ...opFields }),
|
|
66081
|
+
z52.object({ kind: z52.literal("shopify.metafield.delete"), target: target2, payload: metafieldDeleteSchema, ...opFields }),
|
|
66082
|
+
z52.object({ kind: z52.literal("shopify.collection.create"), payload: collectionCreateSchema, ...opFields }),
|
|
66083
|
+
z52.object({ kind: z52.literal("shopify.collection.publish"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
66084
|
+
z52.object({ kind: z52.literal("shopify.collection.unpublish"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
66085
|
+
z52.object({ kind: z52.literal("shopify.collection.update"), target: target2, payload: collectionUpdateSchema, ...opFields }),
|
|
66086
|
+
z52.object({ kind: z52.literal("shopify.collection.delete"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
66087
|
+
z52.object({
|
|
66088
|
+
kind: z52.literal("shopify.collection.addProducts"),
|
|
66089
|
+
target: target2,
|
|
66090
|
+
payload: collectionProductsSchema,
|
|
66091
|
+
...opFields
|
|
66092
|
+
}),
|
|
66093
|
+
z52.object({
|
|
66094
|
+
kind: z52.literal("shopify.collection.removeProducts"),
|
|
66095
|
+
target: target2,
|
|
66096
|
+
payload: collectionProductsSchema,
|
|
66097
|
+
...opFields
|
|
66098
|
+
}),
|
|
66099
|
+
z52.object({ kind: z52.literal("shopify.discountCode.create"), payload: discountCreateSchema, ...opFields }),
|
|
66100
|
+
z52.object({
|
|
66101
|
+
kind: z52.literal("shopify.discountCode.deactivate"),
|
|
66102
|
+
target: target2,
|
|
66103
|
+
payload: emptySchema.optional(),
|
|
66104
|
+
...opFields
|
|
66105
|
+
}),
|
|
66106
|
+
z52.object({ kind: z52.literal("shopify.discountCode.schedule"), target: target2, payload: discountScheduleSchema, ...opFields }),
|
|
66107
|
+
z52.object({ kind: z52.literal("shopify.urlRedirect.create"), payload: urlRedirectCreateSchema, ...opFields }),
|
|
66108
|
+
z52.object({ kind: z52.literal("shopify.urlRedirect.delete"), target: target2, payload: emptySchema.optional(), ...opFields }),
|
|
66109
|
+
z52.object({ kind: z52.literal("shopify.marketingActivity.upsert"), payload: marketingUpsertSchema, ...opFields }),
|
|
66110
|
+
z52.object({
|
|
66111
|
+
kind: z52.literal("shopify.marketingActivity.delete"),
|
|
66112
|
+
target: target2,
|
|
66113
|
+
payload: emptySchema.optional(),
|
|
66114
|
+
...opFields
|
|
66115
|
+
}),
|
|
66116
|
+
z52.object({ kind: z52.literal("shopify.webPixel.update"), payload: emptySchema.optional(), ...opFields }),
|
|
66117
|
+
z52.object({
|
|
66118
|
+
kind: z52.literal("shopify.signupOffer.set"),
|
|
66119
|
+
target: signupOfferHandleSchema,
|
|
66120
|
+
payload: signupOfferSetSchema,
|
|
66121
|
+
...opFields
|
|
66122
|
+
}),
|
|
66123
|
+
z52.object({
|
|
66124
|
+
kind: z52.literal("shopify.signupOffer.end"),
|
|
66125
|
+
target: signupOfferHandleSchema,
|
|
66126
|
+
payload: emptySchema.optional(),
|
|
66127
|
+
...opFields
|
|
66128
|
+
})
|
|
66129
|
+
]);
|
|
66130
|
+
var PAYLOAD_KEYS = new Map(
|
|
66131
|
+
shopifyDraftOpInputSchema.options.map((option) => {
|
|
66132
|
+
const payload = option.shape.payload;
|
|
66133
|
+
const object = payload instanceof z52.ZodOptional ? payload.unwrap() : payload;
|
|
66134
|
+
return [option.shape.kind.value, object instanceof z52.ZodObject ? Object.keys(object.shape) : []];
|
|
66135
|
+
})
|
|
66136
|
+
);
|
|
66137
|
+
var askUserQuestionInputSchema = z52.object({
|
|
66138
|
+
questions: z52.array(
|
|
66139
|
+
z52.object({
|
|
66140
|
+
question: z52.string(),
|
|
66141
|
+
header: z52.string(),
|
|
66142
|
+
multiSelect: z52.boolean(),
|
|
66143
|
+
options: z52.array(z52.object({ label: z52.string(), description: z52.string() })).min(2)
|
|
66144
|
+
})
|
|
66145
|
+
).min(1)
|
|
66146
|
+
});
|
|
66147
|
+
var shopifyNeedsApprovalSchema = z52.object({
|
|
66148
|
+
/** Pass to AskUserQuestion exactly as given. */
|
|
66149
|
+
askUserQuestion: askUserQuestionInputSchema,
|
|
66150
|
+
/** The user already said no to (at least one of) these changes: don't ask again in this turn. */
|
|
66151
|
+
declined: z52.boolean()
|
|
66152
|
+
});
|
|
66153
|
+
var shopifyVerificationSchema = z52.object({
|
|
66154
|
+
status: z52.enum(["confirmed", "drifted", "unconfirmed"]),
|
|
66155
|
+
checkedAt: z52.number(),
|
|
66156
|
+
note: z52.string().optional()
|
|
66157
|
+
});
|
|
66158
|
+
var shopifyDraftOpResultSchema = z52.object({
|
|
66159
|
+
status: z52.enum(["applied", "failed", "skipped"]),
|
|
66160
|
+
createdId: z52.string().optional(),
|
|
66161
|
+
error: z52.string().optional(),
|
|
66162
|
+
note: z52.string().optional(),
|
|
66163
|
+
skippedBecause: z52.string().optional(),
|
|
66164
|
+
executedAt: z52.number().optional(),
|
|
66165
|
+
pendingJob: z52.string().optional(),
|
|
66166
|
+
verification: shopifyVerificationSchema.optional()
|
|
66167
|
+
});
|
|
66168
|
+
var stagedOpSchema = z52.object({
|
|
66169
|
+
ref: z52.string(),
|
|
66170
|
+
kind: shopifyDraftOpKindSchema,
|
|
66171
|
+
summary: z52.string(),
|
|
66172
|
+
warnings: z52.array(z52.string())
|
|
66173
|
+
});
|
|
66174
|
+
var shopifyDraftStageResponseSchema = z52.union([
|
|
66175
|
+
z52.object({
|
|
66176
|
+
staged: z52.literal(true),
|
|
66177
|
+
count: z52.number(),
|
|
66178
|
+
ops: z52.array(stagedOpSchema),
|
|
66179
|
+
amended: z52.boolean().optional()
|
|
66180
|
+
}),
|
|
66181
|
+
z52.object({ staged: z52.literal(false), needsApproval: shopifyNeedsApprovalSchema })
|
|
66182
|
+
]);
|
|
66183
|
+
var SHOPIFY_DRAFT_BATCH_MAX = 100;
|
|
66184
|
+
var shopifyDraftStageRequestSchema = z52.object({ chatId: z52.string(), op: shopifyDraftOpInputSchema });
|
|
66185
|
+
var shopifyDraftStageBatchRequestSchema = z52.object({
|
|
66186
|
+
chatId: z52.string(),
|
|
66187
|
+
ops: z52.array(shopifyDraftOpInputSchema).min(1).max(SHOPIFY_DRAFT_BATCH_MAX)
|
|
66188
|
+
});
|
|
66189
|
+
var shopifyDraftAmendRequestSchema = z52.object({
|
|
66190
|
+
chatId: z52.string(),
|
|
66191
|
+
ref: z52.string(),
|
|
66192
|
+
patch: z52.record(z52.string(), z52.unknown())
|
|
66193
|
+
});
|
|
66194
|
+
var shopifyDraftOpViewSchema = z52.object({
|
|
66195
|
+
ref: z52.string(),
|
|
66196
|
+
kind: shopifyDraftOpKindSchema,
|
|
66197
|
+
entity: shopifyWriteEntitySchema,
|
|
66198
|
+
target: z52.string().optional(),
|
|
66199
|
+
targetLabel: z52.string().optional(),
|
|
66200
|
+
summary: z52.string(),
|
|
66201
|
+
money: z52.boolean(),
|
|
66202
|
+
warnings: z52.array(z52.string()).optional(),
|
|
66203
|
+
dependsOn: z52.array(z52.string()),
|
|
66204
|
+
undoOf: z52.string().optional(),
|
|
66205
|
+
stagedAt: z52.number(),
|
|
66206
|
+
result: shopifyDraftOpResultSchema.optional()
|
|
66207
|
+
});
|
|
66208
|
+
var shopifyDraftListRequestSchema = z52.object({ chatId: z52.string() });
|
|
66209
|
+
var shopifyDraftListResponseSchema = z52.object({
|
|
66210
|
+
status: z52.enum(["active", "publishing", "applied", "discarded", "none"]),
|
|
66211
|
+
store: z52.string().optional(),
|
|
66212
|
+
count: z52.number(),
|
|
66213
|
+
ops: z52.array(shopifyDraftOpViewSchema),
|
|
66214
|
+
publishError: z52.string().optional()
|
|
66215
|
+
});
|
|
66216
|
+
var shopifyDraftShowRequestSchema = z52.object({ chatId: z52.string(), ref: z52.string() });
|
|
66217
|
+
var shopifyDraftShowResponseSchema = z52.object({
|
|
66218
|
+
op: shopifyDraftOpViewSchema.extend({ payload: z52.unknown().optional(), before: z52.unknown().optional() })
|
|
66219
|
+
});
|
|
66220
|
+
var shopifyDraftRemoveRequestSchema = z52.object({ chatId: z52.string(), ref: z52.string() });
|
|
66221
|
+
var shopifyDraftRemoveResponseSchema = z52.object({ removed: z52.array(z52.string()) });
|
|
66222
|
+
var shopifyDraftClearRequestSchema = z52.object({ chatId: z52.string() });
|
|
66223
|
+
var shopifyDraftClearResponseSchema = z52.object({ cleared: z52.number() });
|
|
66224
|
+
var shopifyChangeViewSchema = z52.object({
|
|
66225
|
+
changeId: z52.string(),
|
|
66226
|
+
when: z52.string(),
|
|
66227
|
+
kind: shopifyDraftOpKindSchema,
|
|
66228
|
+
summary: z52.string(),
|
|
66229
|
+
status: z52.enum(["applied", "failed", "undone"]),
|
|
66230
|
+
chatId: z52.string(),
|
|
66231
|
+
undoable: z52.boolean(),
|
|
66232
|
+
/** Why it can't be undone, when it can't. Whether the store still holds Baker's change is checked when undo is staged. */
|
|
66233
|
+
notUndoableBecause: z52.string().optional()
|
|
66234
|
+
});
|
|
66235
|
+
var shopifyChangesRequestSchema = z52.object({
|
|
66236
|
+
limit: z52.coerce.number().int().min(1).max(100).optional(),
|
|
66237
|
+
chatId: z52.string().optional()
|
|
66238
|
+
});
|
|
66239
|
+
var shopifyChangesResponseSchema = z52.object({ changes: z52.array(shopifyChangeViewSchema) });
|
|
66240
|
+
var shopifyUndoRequestSchema = z52.object({
|
|
66241
|
+
chatId: z52.string(),
|
|
66242
|
+
changeIds: z52.array(z52.string().min(1)).min(1).max(SHOPIFY_DRAFT_BATCH_MAX)
|
|
66243
|
+
});
|
|
66244
|
+
|
|
65794
66245
|
// src/commands/shopify/refusal.ts
|
|
65795
66246
|
var CONTINUE2 = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else.";
|
|
65796
66247
|
function shopifyRefusal(code, message) {
|
|
@@ -65815,6 +66266,36 @@ function shopifyRefusal(code, message) {
|
|
|
65815
66266
|
}
|
|
65816
66267
|
return null;
|
|
65817
66268
|
}
|
|
66269
|
+
function storeChangeRefusal(code, message) {
|
|
66270
|
+
if (code !== "FORBIDDEN" || !message.startsWith(SHOPIFY_PERMISSION_NEEDED_PREFIX)) return null;
|
|
66271
|
+
return {
|
|
66272
|
+
code: "SHOPIFY_PERMISSION_NEEDED",
|
|
66273
|
+
fix: {
|
|
66274
|
+
action: "request_connection",
|
|
66275
|
+
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.'
|
|
66276
|
+
}
|
|
66277
|
+
};
|
|
66278
|
+
}
|
|
66279
|
+
function approvalRefusal(needsApproval) {
|
|
66280
|
+
if (needsApproval.declined) {
|
|
66281
|
+
return {
|
|
66282
|
+
code: "NEEDS_USER_APPROVAL",
|
|
66283
|
+
fix: {
|
|
66284
|
+
action: "continue_without",
|
|
66285
|
+
askUserQuestion: needsApproval.askUserQuestion,
|
|
66286
|
+
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."
|
|
66287
|
+
}
|
|
66288
|
+
};
|
|
66289
|
+
}
|
|
66290
|
+
return {
|
|
66291
|
+
code: "NEEDS_USER_APPROVAL",
|
|
66292
|
+
fix: {
|
|
66293
|
+
action: "ask_user",
|
|
66294
|
+
askUserQuestion: needsApproval.askUserQuestion,
|
|
66295
|
+
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.'
|
|
66296
|
+
}
|
|
66297
|
+
};
|
|
66298
|
+
}
|
|
65818
66299
|
|
|
65819
66300
|
// src/commands/shopify/common.ts
|
|
65820
66301
|
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.";
|
|
@@ -65862,7 +66343,7 @@ var fullArg = {
|
|
|
65862
66343
|
|
|
65863
66344
|
// src/commands/shopify/hints.ts
|
|
65864
66345
|
var RECONNECT = 'Baker has lost access to this Shopify store, so these products may be out of date. Say so, and ask the user to reconnect with `request_connection` { platform: "shopify" } \u2014 the card offers Reconnect.';
|
|
65865
|
-
var OWN_STOREFRONT = "This store sells through its own storefront, not a Shopify online store: Baker
|
|
66346
|
+
var OWN_STOREFRONT = "This store sells through its own storefront, not a Shopify online store: Baker links to its product pages once the website's address is set in Brain \u2192 Store (`buyUrlKind` says where each link goes); until then, link to the product pages on the client's own site, and ask the user for them if you don't know them.";
|
|
65866
66347
|
function day(iso) {
|
|
65867
66348
|
return iso ? iso.slice(0, 10) : null;
|
|
65868
66349
|
}
|
|
@@ -65970,17 +66451,17 @@ function stockHintsFor(product) {
|
|
|
65970
66451
|
}
|
|
65971
66452
|
var BUY_NOTES = {
|
|
65972
66453
|
password_protected: "The store asks for a password before anyone can see it: a shopper following a buy link meets it first \u2014 tell the user before sending traffic.",
|
|
65973
|
-
subscription_optional: "It can also be bought by subscription
|
|
65974
|
-
own_storefront: "The store sells through its own
|
|
66454
|
+
subscription_optional: "It can also be bought by subscription: on a landing `<ShopifyProduct>` offers the plans; a `buyUrl` elsewhere adds it once.",
|
|
66455
|
+
own_storefront: "The store sells through its own website: `buyUrlKind` says where each link goes \u2014 its product page, or its cart page once its developers confirm it in Brain \u2192 Store.",
|
|
65975
66456
|
details_pending: "Baker hasn't read this product's details yet (subscriptions among them): its buy links may change.",
|
|
65976
|
-
subscription_only: "It's sold only by subscription
|
|
66457
|
+
subscription_only: "It's sold only by subscription: on a landing `<ShopifyProduct>` offers the plans; a `buyUrl` elsewhere is its product page, where the shopper picks one."
|
|
65977
66458
|
};
|
|
65978
66459
|
function buyHints(product) {
|
|
65979
66460
|
const hints2 = [];
|
|
65980
66461
|
if (product.variants.some((variant) => variant.buyUrl)) {
|
|
65981
66462
|
hints2.push(
|
|
65982
|
-
`
|
|
65983
|
-
|
|
66463
|
+
`On a landing, place \`<ShopifyProduct product="${product.handle}" />\` (and \`<ShopifyBuyButton product="${product.handle}">\` for a second button): it shows the options, price and stock, and its button hands the shopper to the store. Never put a \`buyUrl\` on a landing yourself, and never build an option picker. See /landing \`.claude/skills/landing/references/verticals/ecommerce.md\`.`,
|
|
66464
|
+
`\`buyUrl\` is for links outside a landing \u2014 an ad, an email, a message: one per option; never \`storeUrl\` (a page to look at), never a Shopify link built yourself (it follows the store's setting: ${product.buyDestination.replace("_", " ")}; \`--quantity <n>\` sets how many).`
|
|
65984
66465
|
);
|
|
65985
66466
|
}
|
|
65986
66467
|
const notes = new Set(product.variants.flatMap((variant) => variant.notes ?? []));
|
|
@@ -66435,18 +66916,899 @@ var segmentsCommand = defineCommand209({
|
|
|
66435
66916
|
}
|
|
66436
66917
|
});
|
|
66437
66918
|
|
|
66438
|
-
// src/commands/shopify/
|
|
66919
|
+
// src/commands/shopify/change.ts
|
|
66920
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
66921
|
+
|
|
66922
|
+
// src/commands/shopify/writeCommon.ts
|
|
66439
66923
|
import { defineCommand as defineCommand210 } from "citty";
|
|
66440
66924
|
|
|
66925
|
+
// src/commands/shopify/writeHints.ts
|
|
66926
|
+
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.";
|
|
66927
|
+
var WARNINGS = "Read the warnings above before telling the user this is ready.";
|
|
66928
|
+
var DISCOUNT = "The code works only after the chat is published; don't announce it as live or share it as working yet.";
|
|
66929
|
+
var EMPTY_COLLECTION = "The new collection has no products yet: add them with `baker shopify change collection add <collection> <product\u2026>`.";
|
|
66930
|
+
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).";
|
|
66931
|
+
function repointedRedirects(ops) {
|
|
66932
|
+
const removed = ops.flatMap(
|
|
66933
|
+
(op) => op.kind === "shopify.urlRedirect.delete" && op.ref.startsWith("urlRedirect:") ? [op.ref.slice("urlRedirect:".length)] : []
|
|
66934
|
+
);
|
|
66935
|
+
return removed.flatMap((path49) => {
|
|
66936
|
+
const made = ops.find(
|
|
66937
|
+
(op) => op.kind === "shopify.urlRedirect.create" && op.summary.startsWith(`Redirect ${path49} to `)
|
|
66938
|
+
);
|
|
66939
|
+
if (!made) return [];
|
|
66940
|
+
const to = made.summary.slice(`Redirect ${path49} to `.length);
|
|
66941
|
+
return [
|
|
66942
|
+
`${path49} still redirects after publish, now to ${to}: tell the user the old link goes there, not that its redirect is removed.`
|
|
66943
|
+
];
|
|
66944
|
+
});
|
|
66945
|
+
}
|
|
66946
|
+
function stageHints(data) {
|
|
66947
|
+
if (!data.staged) return [];
|
|
66948
|
+
const hints2 = [STAGED, ...repointedRedirects(data.ops)];
|
|
66949
|
+
if (data.ops.some((op) => op.warnings.length > 0)) hints2.push(WARNINGS);
|
|
66950
|
+
if (data.ops.some((op) => op.kind === "shopify.discountCode.create")) hints2.push(DISCOUNT);
|
|
66951
|
+
if (data.ops.some((op) => op.kind === "shopify.collection.delete")) hints2.push(COLLECTION_DELETE);
|
|
66952
|
+
if (data.ops.some(
|
|
66953
|
+
(op) => op.kind === "shopify.collection.create" && op.warnings.some((warning) => /no products/.test(warning))
|
|
66954
|
+
)) {
|
|
66955
|
+
hints2.push(EMPTY_COLLECTION);
|
|
66956
|
+
}
|
|
66957
|
+
return hints2;
|
|
66958
|
+
}
|
|
66959
|
+
function changesHints(data) {
|
|
66960
|
+
if (data.changes.length === 0) return ["Baker hasn't changed this store yet."];
|
|
66961
|
+
return data.changes.some((change) => change.undoable) ? ["Undo one with `baker shopify undo <changeId>` (staged like any change, applied when the user publishes)."] : [];
|
|
66962
|
+
}
|
|
66963
|
+
function auditHints(data) {
|
|
66964
|
+
const hints2 = [];
|
|
66965
|
+
for (const check of data.checks) {
|
|
66966
|
+
if (check.fix?.kind === "staged") hints2.push(`Stage the fix for "${check.title}": \`${check.fix.command}\`.`);
|
|
66967
|
+
}
|
|
66968
|
+
for (const check of data.checks) {
|
|
66969
|
+
if (check.fix?.kind === "merchant") {
|
|
66970
|
+
hints2.push(
|
|
66971
|
+
`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" : ""}.`
|
|
66972
|
+
);
|
|
66973
|
+
}
|
|
66974
|
+
}
|
|
66975
|
+
for (const check of data.checks) {
|
|
66976
|
+
if (check.fix?.kind === "decision") hints2.push(`A person decides "${check.title}": ${check.fix.where}.`);
|
|
66977
|
+
}
|
|
66978
|
+
return hints2;
|
|
66979
|
+
}
|
|
66980
|
+
|
|
66981
|
+
// src/commands/shopify/writeCommon.ts
|
|
66982
|
+
function failChange(err) {
|
|
66983
|
+
if (err instanceof ApiError) {
|
|
66984
|
+
const refusal = storeChangeRefusal(err.code, err.message);
|
|
66985
|
+
if (refusal) {
|
|
66986
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
66987
|
+
process.exit(1);
|
|
66988
|
+
}
|
|
66989
|
+
}
|
|
66990
|
+
fail9(err);
|
|
66991
|
+
}
|
|
66992
|
+
function emitStage(data) {
|
|
66993
|
+
if (!data.staged) {
|
|
66994
|
+
const refusal = approvalRefusal(data.needsApproval);
|
|
66995
|
+
writeJson({
|
|
66996
|
+
ok: false,
|
|
66997
|
+
error: {
|
|
66998
|
+
code: refusal.code,
|
|
66999
|
+
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.",
|
|
67000
|
+
fix: refusal.fix
|
|
67001
|
+
}
|
|
67002
|
+
});
|
|
67003
|
+
process.exit(1);
|
|
67004
|
+
}
|
|
67005
|
+
writeJson({ ok: true, hints: stageHints(data), data });
|
|
67006
|
+
}
|
|
67007
|
+
async function stage(ops) {
|
|
67008
|
+
const chatId = requireChatId();
|
|
67009
|
+
try {
|
|
67010
|
+
const [only] = ops;
|
|
67011
|
+
const data = ops.length === 1 && only ? await apiPost("/api/shopify/draft/stage", { chatId, op: only }) : await apiPost("/api/shopify/draft/stage-batch", { chatId, ops });
|
|
67012
|
+
emitStage(data);
|
|
67013
|
+
} catch (err) {
|
|
67014
|
+
failChange(err);
|
|
67015
|
+
}
|
|
67016
|
+
}
|
|
67017
|
+
function list(value) {
|
|
67018
|
+
if (typeof value !== "string" || value.trim() === "") return void 0;
|
|
67019
|
+
return value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
67020
|
+
}
|
|
67021
|
+
function defined(entries) {
|
|
67022
|
+
return Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== void 0 && value !== ""));
|
|
67023
|
+
}
|
|
67024
|
+
function payloadsFrom(args5) {
|
|
67025
|
+
if (typeof args5.json !== "string" && typeof args5.file !== "string") return null;
|
|
67026
|
+
return loadJsonPayloads(args5);
|
|
67027
|
+
}
|
|
67028
|
+
var JSON_ARGS = {
|
|
67029
|
+
json: {
|
|
67030
|
+
type: "string",
|
|
67031
|
+
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',
|
|
67032
|
+
required: false
|
|
67033
|
+
},
|
|
67034
|
+
file: { type: "string", description: "A JSON file holding the same", required: false }
|
|
67035
|
+
};
|
|
67036
|
+
function leaf(schemaName, meta, args5, run) {
|
|
67037
|
+
registerSchema({
|
|
67038
|
+
command: schemaName,
|
|
67039
|
+
description: meta.description,
|
|
67040
|
+
args: Object.fromEntries(
|
|
67041
|
+
Object.entries(args5).map(([name, arg]) => [
|
|
67042
|
+
name,
|
|
67043
|
+
{
|
|
67044
|
+
type: String(arg.type ?? "string"),
|
|
67045
|
+
description: String(arg.description ?? ""),
|
|
67046
|
+
required: arg.required === true
|
|
67047
|
+
}
|
|
67048
|
+
])
|
|
67049
|
+
)
|
|
67050
|
+
});
|
|
67051
|
+
return defineCommand210({ meta, args: args5, run: async ({ args: parsed }) => await run(parsed) });
|
|
67052
|
+
}
|
|
67053
|
+
|
|
67054
|
+
// src/commands/shopify/change.ts
|
|
67055
|
+
var TARGET = (what) => ({ type: "positional", description: what, required: false });
|
|
67056
|
+
function positionals(args5) {
|
|
67057
|
+
return Array.isArray(args5._) ? args5._.filter((value) => typeof value === "string") : [];
|
|
67058
|
+
}
|
|
67059
|
+
function target3(args5, what) {
|
|
67060
|
+
const [first] = positionals(args5);
|
|
67061
|
+
if (!first) failValidation3(`pass the ${what} as the first argument`);
|
|
67062
|
+
return first;
|
|
67063
|
+
}
|
|
67064
|
+
async function stageFor(kind, args5, flags, targetOf) {
|
|
67065
|
+
const payloads = payloadsFrom(args5);
|
|
67066
|
+
if (payloads) {
|
|
67067
|
+
await stage(
|
|
67068
|
+
payloads.map(
|
|
67069
|
+
(payload2) => "kind" in payload2 ? payload2 : { kind, ...targetOf ? { target: targetOf() } : {}, payload: payload2 }
|
|
67070
|
+
)
|
|
67071
|
+
);
|
|
67072
|
+
return;
|
|
67073
|
+
}
|
|
67074
|
+
const payload = flags();
|
|
67075
|
+
if (Object.keys(payload).length === 0)
|
|
67076
|
+
failValidation3("name at least one thing to change (see `baker schema` for the flags)");
|
|
67077
|
+
await stage([{ kind, ...targetOf ? { target: targetOf() } : {}, payload }]);
|
|
67078
|
+
}
|
|
67079
|
+
var productUpdate = leaf(
|
|
67080
|
+
"shopify.change.product.update",
|
|
67081
|
+
{
|
|
67082
|
+
name: "update",
|
|
67083
|
+
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.`
|
|
67084
|
+
},
|
|
67085
|
+
{
|
|
67086
|
+
product: TARGET("Product id, handle or link"),
|
|
67087
|
+
title: { type: "string", description: "New title", required: false },
|
|
67088
|
+
description: { type: "string", description: "New description, as HTML (no scripts or frames)", required: false },
|
|
67089
|
+
"seo-title": { type: "string", description: "Title shown in search results", required: false },
|
|
67090
|
+
"seo-description": { type: "string", description: "Description shown in search results", required: false },
|
|
67091
|
+
tags: { type: "string", description: "The whole tag list, comma separated (replaces it)", required: false },
|
|
67092
|
+
"add-tags": { type: "string", description: "Tags to add, comma separated", required: false },
|
|
67093
|
+
"remove-tags": { type: "string", description: "Tags to remove, comma separated", required: false },
|
|
67094
|
+
type: { type: "string", description: "Product type", required: false },
|
|
67095
|
+
...JSON_ARGS
|
|
67096
|
+
},
|
|
67097
|
+
async (args5) => await stageFor(
|
|
67098
|
+
"shopify.product.update",
|
|
67099
|
+
args5,
|
|
67100
|
+
() => defined({
|
|
67101
|
+
title: args5.title,
|
|
67102
|
+
descriptionHtml: args5.description,
|
|
67103
|
+
seo: args5["seo-title"] !== void 0 || args5["seo-description"] !== void 0 ? defined({ title: args5["seo-title"], description: args5["seo-description"] }) : void 0,
|
|
67104
|
+
tags: list(args5.tags),
|
|
67105
|
+
addTags: list(args5["add-tags"]),
|
|
67106
|
+
removeTags: list(args5["remove-tags"]),
|
|
67107
|
+
productType: args5.type
|
|
67108
|
+
}),
|
|
67109
|
+
positionals(args5).length > 0 ? () => target3(args5, "product") : void 0
|
|
67110
|
+
)
|
|
67111
|
+
);
|
|
67112
|
+
var WEIGHT_UNITS = {
|
|
67113
|
+
g: "GRAMS",
|
|
67114
|
+
gram: "GRAMS",
|
|
67115
|
+
grams: "GRAMS",
|
|
67116
|
+
kg: "KILOGRAMS",
|
|
67117
|
+
kgs: "KILOGRAMS",
|
|
67118
|
+
kilogram: "KILOGRAMS",
|
|
67119
|
+
kilograms: "KILOGRAMS",
|
|
67120
|
+
oz: "OUNCES",
|
|
67121
|
+
ounce: "OUNCES",
|
|
67122
|
+
ounces: "OUNCES",
|
|
67123
|
+
lb: "POUNDS",
|
|
67124
|
+
lbs: "POUNDS",
|
|
67125
|
+
pound: "POUNDS",
|
|
67126
|
+
pounds: "POUNDS"
|
|
67127
|
+
};
|
|
67128
|
+
function weightOf(value, unit) {
|
|
67129
|
+
if (value === void 0) return void 0;
|
|
67130
|
+
const named = typeof unit === "string" ? unit.trim() : "";
|
|
67131
|
+
return {
|
|
67132
|
+
value: Number(value),
|
|
67133
|
+
unit: named ? WEIGHT_UNITS[named.toLowerCase()] ?? named.toUpperCase() : "KILOGRAMS"
|
|
67134
|
+
};
|
|
67135
|
+
}
|
|
67136
|
+
var variantUpdate = leaf(
|
|
67137
|
+
"shopify.change.variant.update",
|
|
67138
|
+
{
|
|
67139
|
+
name: "update",
|
|
67140
|
+
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."
|
|
67141
|
+
},
|
|
67142
|
+
{
|
|
67143
|
+
variant: TARGET("The option's id (variantId from baker shopify product)"),
|
|
67144
|
+
sku: { type: "string", description: "SKU", required: false },
|
|
67145
|
+
barcode: { type: "string", description: "Barcode / GTIN (8, 12, 13 or 14 digits)", required: false },
|
|
67146
|
+
weight: { type: "string", description: "Weight value", required: false },
|
|
67147
|
+
"weight-unit": {
|
|
67148
|
+
type: "string",
|
|
67149
|
+
description: "kg | g | lb | oz (default kg)",
|
|
67150
|
+
required: false
|
|
67151
|
+
},
|
|
67152
|
+
price: {
|
|
67153
|
+
type: "string",
|
|
67154
|
+
description: `Price as a decimal, e.g. "649.95" (needs the user's yes)`,
|
|
67155
|
+
required: false
|
|
67156
|
+
},
|
|
67157
|
+
"sale-price": {
|
|
67158
|
+
type: "string",
|
|
67159
|
+
description: `Compare-at price, or "none" to clear it (needs the user's yes)`,
|
|
67160
|
+
required: false
|
|
67161
|
+
},
|
|
67162
|
+
...JSON_ARGS
|
|
67163
|
+
},
|
|
67164
|
+
async (args5) => await stageFor(
|
|
67165
|
+
"shopify.variant.update",
|
|
67166
|
+
args5,
|
|
67167
|
+
() => defined({
|
|
67168
|
+
sku: args5.sku,
|
|
67169
|
+
barcode: args5.barcode,
|
|
67170
|
+
weight: weightOf(args5.weight, args5["weight-unit"]),
|
|
67171
|
+
price: args5.price,
|
|
67172
|
+
compareAtPrice: args5["sale-price"] === "none" ? null : args5["sale-price"]
|
|
67173
|
+
}),
|
|
67174
|
+
positionals(args5).length > 0 ? () => target3(args5, "option id") : void 0
|
|
67175
|
+
)
|
|
67176
|
+
);
|
|
67177
|
+
var fieldSet = leaf(
|
|
67178
|
+
"shopify.change.field.set",
|
|
67179
|
+
{
|
|
67180
|
+
name: "set",
|
|
67181
|
+
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".'
|
|
67182
|
+
},
|
|
67183
|
+
{
|
|
67184
|
+
owner: TARGET("product:<ref>, variant:<id> or collection:<ref>"),
|
|
67185
|
+
namespace: { type: "string", description: "Namespace, e.g. custom", required: false },
|
|
67186
|
+
key: { type: "string", description: "Key, e.g. care", required: false },
|
|
67187
|
+
type: {
|
|
67188
|
+
type: "string",
|
|
67189
|
+
description: "Shopify's type, e.g. single_line_text_field, rich_text_field, json",
|
|
67190
|
+
required: false
|
|
67191
|
+
},
|
|
67192
|
+
value: { type: "string", description: "The value, as Shopify takes it for that type", required: false },
|
|
67193
|
+
...JSON_ARGS
|
|
67194
|
+
},
|
|
67195
|
+
async (args5) => await stageFor(
|
|
67196
|
+
"shopify.metafield.set",
|
|
67197
|
+
args5,
|
|
67198
|
+
() => defined({ namespace: args5.namespace, key: args5.key, type: args5.type, value: args5.value }),
|
|
67199
|
+
() => target3(args5, "owner")
|
|
67200
|
+
)
|
|
67201
|
+
);
|
|
67202
|
+
var fieldRemove = leaf(
|
|
67203
|
+
"shopify.change.field.remove",
|
|
67204
|
+
{
|
|
67205
|
+
name: "remove",
|
|
67206
|
+
description: "Remove a custom field from a product, an option or a collection. Example: baker shopify change field remove product:the-snowboard custom.care"
|
|
67207
|
+
},
|
|
67208
|
+
{
|
|
67209
|
+
owner: TARGET("product:<ref>, variant:<id> or collection:<ref>"),
|
|
67210
|
+
field: TARGET("namespace.key, e.g. custom.care")
|
|
67211
|
+
},
|
|
67212
|
+
async (args5) => {
|
|
67213
|
+
const [owner, field] = positionals(args5);
|
|
67214
|
+
const [namespace, ...rest] = (field ?? "").split(".");
|
|
67215
|
+
if (!owner || !namespace || rest.length === 0) failValidation3("pass the owner and the field as namespace.key");
|
|
67216
|
+
await stage([{ kind: "shopify.metafield.delete", target: owner, payload: { namespace, key: rest.join(".") } }]);
|
|
67217
|
+
}
|
|
67218
|
+
);
|
|
67219
|
+
var collectionCreate = leaf(
|
|
67220
|
+
"shopify.change.collection.create",
|
|
67221
|
+
{
|
|
67222
|
+
name: "create",
|
|
67223
|
+
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.'
|
|
67224
|
+
},
|
|
67225
|
+
{
|
|
67226
|
+
title: { type: "string", description: "Title", required: false },
|
|
67227
|
+
handle: {
|
|
67228
|
+
type: "string",
|
|
67229
|
+
description: "Its address (/collections/<handle>); default from the title",
|
|
67230
|
+
required: false
|
|
67231
|
+
},
|
|
67232
|
+
description: { type: "string", description: "Description, as HTML (no scripts or frames)", required: false },
|
|
67233
|
+
"seo-title": { type: "string", description: "Title shown in search results", required: false },
|
|
67234
|
+
"seo-description": { type: "string", description: "Description shown in search results", required: false },
|
|
67235
|
+
products: {
|
|
67236
|
+
type: "string",
|
|
67237
|
+
description: "Products, comma separated (ids, handles or links), in order",
|
|
67238
|
+
required: false
|
|
67239
|
+
},
|
|
67240
|
+
sort: {
|
|
67241
|
+
type: "string",
|
|
67242
|
+
description: "MANUAL | BEST_SELLING | ALPHA_ASC | ALPHA_DESC | PRICE_ASC | PRICE_DESC | CREATED | CREATED_DESC",
|
|
67243
|
+
required: false
|
|
67244
|
+
},
|
|
67245
|
+
hidden: { type: "boolean", description: "Don't show it on the online store yet", required: false },
|
|
67246
|
+
...JSON_ARGS
|
|
67247
|
+
},
|
|
67248
|
+
async (args5) => await stageFor(
|
|
67249
|
+
"shopify.collection.create",
|
|
67250
|
+
args5,
|
|
67251
|
+
() => defined({
|
|
67252
|
+
title: args5.title,
|
|
67253
|
+
handle: args5.handle,
|
|
67254
|
+
descriptionHtml: args5.description,
|
|
67255
|
+
seo: args5["seo-title"] !== void 0 || args5["seo-description"] !== void 0 ? defined({ title: args5["seo-title"], description: args5["seo-description"] }) : void 0,
|
|
67256
|
+
products: list(args5.products),
|
|
67257
|
+
sortOrder: typeof args5.sort === "string" ? args5.sort.toUpperCase() : void 0,
|
|
67258
|
+
onlineStore: args5.hidden === true ? false : void 0
|
|
67259
|
+
})
|
|
67260
|
+
)
|
|
67261
|
+
);
|
|
67262
|
+
var collectionUpdate = leaf(
|
|
67263
|
+
"shopify.change.collection.update",
|
|
67264
|
+
{
|
|
67265
|
+
name: "update",
|
|
67266
|
+
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"`
|
|
67267
|
+
},
|
|
67268
|
+
{
|
|
67269
|
+
collection: TARGET("Collection id, handle or link"),
|
|
67270
|
+
title: { type: "string", description: "New title", required: false },
|
|
67271
|
+
description: { type: "string", description: "New description, as HTML", required: false },
|
|
67272
|
+
"seo-title": { type: "string", description: "Title shown in search results", required: false },
|
|
67273
|
+
"seo-description": { type: "string", description: "Description shown in search results", required: false },
|
|
67274
|
+
sort: { type: "string", description: "Sort order (see collection create)", required: false },
|
|
67275
|
+
...JSON_ARGS
|
|
67276
|
+
},
|
|
67277
|
+
async (args5) => await stageFor(
|
|
67278
|
+
"shopify.collection.update",
|
|
67279
|
+
args5,
|
|
67280
|
+
() => defined({
|
|
67281
|
+
title: args5.title,
|
|
67282
|
+
descriptionHtml: args5.description,
|
|
67283
|
+
seo: args5["seo-title"] !== void 0 || args5["seo-description"] !== void 0 ? defined({ title: args5["seo-title"], description: args5["seo-description"] }) : void 0,
|
|
67284
|
+
sortOrder: typeof args5.sort === "string" ? args5.sort.toUpperCase() : void 0
|
|
67285
|
+
}),
|
|
67286
|
+
() => target3(args5, "collection")
|
|
67287
|
+
)
|
|
67288
|
+
);
|
|
67289
|
+
function collectionVerb(verb, kind, description2) {
|
|
67290
|
+
return leaf(
|
|
67291
|
+
`shopify.change.collection.${verb}`,
|
|
67292
|
+
{ name: verb, description: description2 },
|
|
67293
|
+
{ collection: TARGET("Collection id, handle, link or a shopify_temp_ ref staged in this chat") },
|
|
67294
|
+
async (args5) => await stage([{ kind, target: target3(args5, "collection") }])
|
|
67295
|
+
);
|
|
67296
|
+
}
|
|
67297
|
+
function membership(verb, kind, description2) {
|
|
67298
|
+
return leaf(
|
|
67299
|
+
`shopify.change.collection.${verb}`,
|
|
67300
|
+
{ name: verb, description: description2 },
|
|
67301
|
+
{
|
|
67302
|
+
collection: TARGET("Collection id, handle, link or a shopify_temp_ ref"),
|
|
67303
|
+
products: TARGET("Products (ids, handles or links), space separated")
|
|
67304
|
+
},
|
|
67305
|
+
async (args5) => {
|
|
67306
|
+
const [collection, ...products] = positionals(args5);
|
|
67307
|
+
if (!collection || products.length === 0) failValidation3("pass the collection, then the products");
|
|
67308
|
+
await stage([{ kind, target: collection, payload: { products } }]);
|
|
67309
|
+
}
|
|
67310
|
+
);
|
|
67311
|
+
}
|
|
67312
|
+
function discountValue(args5) {
|
|
67313
|
+
if (args5.percent !== void 0) return { percentage: Number(args5.percent) };
|
|
67314
|
+
if (args5.amount !== void 0) return { amount: args5.amount };
|
|
67315
|
+
return void 0;
|
|
67316
|
+
}
|
|
67317
|
+
function appliesToOf(args5) {
|
|
67318
|
+
const products = list(args5.products);
|
|
67319
|
+
if (products) return { products };
|
|
67320
|
+
const collections = list(args5.collections);
|
|
67321
|
+
return collections ? { collections } : { all: true };
|
|
67322
|
+
}
|
|
67323
|
+
function combinesOf(value) {
|
|
67324
|
+
const combines = list(value) ?? [];
|
|
67325
|
+
if (combines.length === 0) return void 0;
|
|
67326
|
+
return {
|
|
67327
|
+
productDiscounts: combines.includes("product"),
|
|
67328
|
+
orderDiscounts: combines.includes("order"),
|
|
67329
|
+
shippingDiscounts: combines.includes("shipping")
|
|
67330
|
+
};
|
|
67331
|
+
}
|
|
67332
|
+
function numberOf3(value) {
|
|
67333
|
+
return value === void 0 ? void 0 : Number(value);
|
|
67334
|
+
}
|
|
67335
|
+
function discountPayload(args5) {
|
|
67336
|
+
return defined({
|
|
67337
|
+
code: args5.code,
|
|
67338
|
+
title: args5.title,
|
|
67339
|
+
value: discountValue(args5),
|
|
67340
|
+
appliesTo: appliesToOf(args5),
|
|
67341
|
+
minimumSubtotal: args5["min-subtotal"],
|
|
67342
|
+
minimumQuantity: numberOf3(args5["min-quantity"]),
|
|
67343
|
+
startsAt: args5.starts,
|
|
67344
|
+
endsAt: args5.ends,
|
|
67345
|
+
usageLimit: numberOf3(args5.limit),
|
|
67346
|
+
oncePerCustomer: args5["any-times"] === true ? false : void 0,
|
|
67347
|
+
combinesWith: combinesOf(args5.combines)
|
|
67348
|
+
});
|
|
67349
|
+
}
|
|
67350
|
+
function signupOfferFlagsProblem(args5) {
|
|
67351
|
+
if (typeof args5.name !== "string" || args5.name.trim() === "")
|
|
67352
|
+
return 'Add --name "<what shoppers and store staff see, e.g. 10% off>": every sign-up offer needs a name.';
|
|
67353
|
+
if (args5["valid-days"] === void 0)
|
|
67354
|
+
return "Add --valid-days <1-365>: how many days each code lasts after it is given.";
|
|
67355
|
+
return void 0;
|
|
67356
|
+
}
|
|
67357
|
+
function signupOfferPayload(args5) {
|
|
67358
|
+
return defined({
|
|
67359
|
+
name: args5.name,
|
|
67360
|
+
value: discountValue(args5),
|
|
67361
|
+
appliesTo: appliesToOf(args5),
|
|
67362
|
+
minimumSubtotal: args5.minimum,
|
|
67363
|
+
validForDays: numberOf3(args5["valid-days"]),
|
|
67364
|
+
endsAt: args5.ends,
|
|
67365
|
+
maxCodes: numberOf3(args5["max-codes"]),
|
|
67366
|
+
codePrefix: args5.prefix,
|
|
67367
|
+
combinesWith: combinesOf(args5.combines)
|
|
67368
|
+
});
|
|
67369
|
+
}
|
|
67370
|
+
var signupOfferSet = leaf(
|
|
67371
|
+
"shopify.change.signupOffer.set",
|
|
67372
|
+
{
|
|
67373
|
+
name: "set",
|
|
67374
|
+
description: 'Stage a sign-up offer. Changes money: ask the exact approval question returned by this command. Example: baker shopify change signup-offer set welcome-10 --name "Welcome" --percent 10 --valid-days 14 --max-codes 1000'
|
|
67375
|
+
},
|
|
67376
|
+
{
|
|
67377
|
+
handle: TARGET("Offer handle, e.g. welcome-10"),
|
|
67378
|
+
name: {
|
|
67379
|
+
type: "string",
|
|
67380
|
+
description: 'Offer name shoppers and store staff see (required), e.g. "10% off"',
|
|
67381
|
+
required: false
|
|
67382
|
+
},
|
|
67383
|
+
percent: { type: "string", description: "Percentage off (choose percent or amount)", required: false },
|
|
67384
|
+
amount: { type: "string", description: "Amount off in the store currency", required: false },
|
|
67385
|
+
products: { type: "string", description: "Product handles or ids, comma separated", required: false },
|
|
67386
|
+
collections: { type: "string", description: "Collection handles or ids, comma separated", required: false },
|
|
67387
|
+
minimum: { type: "string", description: "Minimum subtotal", required: false },
|
|
67388
|
+
"valid-days": { type: "string", description: "Each code lasts 1\u2013365 days (required)", required: false },
|
|
67389
|
+
ends: { type: "string", description: "Offer end as ISO date and time; no code outlives it", required: false },
|
|
67390
|
+
"max-codes": { type: "string", description: "Total codes the offer may give, 1\u2013100000", required: false },
|
|
67391
|
+
prefix: { type: "string", description: "Code prefix: 2\u201312 uppercase letters or digits", required: false },
|
|
67392
|
+
combines: {
|
|
67393
|
+
type: "string",
|
|
67394
|
+
description: "Comma-separated product,order,shipping discounts to combine",
|
|
67395
|
+
required: false
|
|
67396
|
+
},
|
|
67397
|
+
...JSON_ARGS
|
|
67398
|
+
},
|
|
67399
|
+
async (args5) => await stageFor(
|
|
67400
|
+
"shopify.signupOffer.set",
|
|
67401
|
+
args5,
|
|
67402
|
+
() => {
|
|
67403
|
+
const problem = signupOfferFlagsProblem(args5);
|
|
67404
|
+
if (problem) failValidation3(problem);
|
|
67405
|
+
return signupOfferPayload(args5);
|
|
67406
|
+
},
|
|
67407
|
+
() => target3(args5, "offer handle")
|
|
67408
|
+
)
|
|
67409
|
+
);
|
|
67410
|
+
var signupOfferEnd = leaf(
|
|
67411
|
+
"shopify.change.signupOffer.end",
|
|
67412
|
+
{
|
|
67413
|
+
name: "end",
|
|
67414
|
+
description: "End a sign-up offer at Publish. Existing codes keep their terms. Example: baker shopify change signup-offer end welcome-10"
|
|
67415
|
+
},
|
|
67416
|
+
{ handle: TARGET("Offer handle") },
|
|
67417
|
+
async (args5) => await stage([{ kind: "shopify.signupOffer.end", target: target3(args5, "offer handle") }])
|
|
67418
|
+
);
|
|
67419
|
+
var discountCreate = leaf(
|
|
67420
|
+
"shopify.change.discount.create",
|
|
67421
|
+
{
|
|
67422
|
+
name: "create",
|
|
67423
|
+
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."
|
|
67424
|
+
},
|
|
67425
|
+
{
|
|
67426
|
+
code: { type: "string", description: "The code shoppers type, e.g. SPRING10", required: false },
|
|
67427
|
+
title: { type: "string", description: "What the store's staff see (default: the code)", required: false },
|
|
67428
|
+
percent: { type: "string", description: "Percentage off, 1-100", required: false },
|
|
67429
|
+
amount: { type: "string", description: "Amount off, as a decimal in the store's currency", required: false },
|
|
67430
|
+
products: { type: "string", description: "Only these products, comma separated", required: false },
|
|
67431
|
+
collections: { type: "string", description: "Only these collections, comma separated", required: false },
|
|
67432
|
+
"min-subtotal": { type: "string", description: "Minimum order amount", required: false },
|
|
67433
|
+
"min-quantity": { type: "string", description: "Minimum number of items", required: false },
|
|
67434
|
+
starts: { type: "string", description: "Start, ISO date-time (default: when published)", required: false },
|
|
67435
|
+
ends: { type: "string", description: "End, ISO date-time (default: no end)", required: false },
|
|
67436
|
+
limit: { type: "string", description: "Total number of uses", required: false },
|
|
67437
|
+
"any-times": { type: "boolean", description: "A customer may use it more than once", required: false },
|
|
67438
|
+
combines: {
|
|
67439
|
+
type: "string",
|
|
67440
|
+
description: "What it combines with, comma separated: product, order, shipping",
|
|
67441
|
+
required: false
|
|
67442
|
+
},
|
|
67443
|
+
...JSON_ARGS
|
|
67444
|
+
},
|
|
67445
|
+
async (args5) => await stageFor("shopify.discountCode.create", args5, () => discountPayload(args5))
|
|
67446
|
+
);
|
|
67447
|
+
var discountStop = leaf(
|
|
67448
|
+
"shopify.change.discount.stop",
|
|
67449
|
+
{
|
|
67450
|
+
name: "stop",
|
|
67451
|
+
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"
|
|
67452
|
+
},
|
|
67453
|
+
{ code: TARGET("The discount code") },
|
|
67454
|
+
async (args5) => await stage([{ kind: "shopify.discountCode.deactivate", target: target3(args5, "code") }])
|
|
67455
|
+
);
|
|
67456
|
+
var discountDates = leaf(
|
|
67457
|
+
"shopify.change.discount.dates",
|
|
67458
|
+
{
|
|
67459
|
+
name: "dates",
|
|
67460
|
+
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"
|
|
67461
|
+
},
|
|
67462
|
+
{
|
|
67463
|
+
code: TARGET("The discount code"),
|
|
67464
|
+
starts: { type: "string", description: "Start, ISO date-time", required: false },
|
|
67465
|
+
ends: { type: "string", description: 'End, ISO date-time, or "never"', required: false }
|
|
67466
|
+
},
|
|
67467
|
+
async (args5) => {
|
|
67468
|
+
if (typeof args5.starts !== "string" || typeof args5.ends !== "string") failValidation3("pass --starts and --ends");
|
|
67469
|
+
await stage([
|
|
67470
|
+
{
|
|
67471
|
+
kind: "shopify.discountCode.schedule",
|
|
67472
|
+
target: target3(args5, "code"),
|
|
67473
|
+
payload: { startsAt: args5.starts, endsAt: args5.ends === "never" ? null : args5.ends }
|
|
67474
|
+
}
|
|
67475
|
+
]);
|
|
67476
|
+
}
|
|
67477
|
+
);
|
|
67478
|
+
var redirectCreate = leaf(
|
|
67479
|
+
"shopify.change.redirect.create",
|
|
67480
|
+
{
|
|
67481
|
+
name: "create",
|
|
67482
|
+
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"
|
|
67483
|
+
},
|
|
67484
|
+
{
|
|
67485
|
+
from: { type: "string", description: "The old path, starting with /", required: false },
|
|
67486
|
+
to: { type: "string", description: "Where it sends shoppers: a path or an https link", required: false },
|
|
67487
|
+
...JSON_ARGS
|
|
67488
|
+
},
|
|
67489
|
+
async (args5) => await stageFor("shopify.urlRedirect.create", args5, () => defined({ from: args5.from, to: args5.to }))
|
|
67490
|
+
);
|
|
67491
|
+
var redirectRemove = leaf(
|
|
67492
|
+
"shopify.change.redirect.remove",
|
|
67493
|
+
{
|
|
67494
|
+
name: "remove",
|
|
67495
|
+
description: "Remove a redirect, by the path it redirects. Example: baker shopify change redirect remove /old"
|
|
67496
|
+
},
|
|
67497
|
+
{ from: TARGET("The redirected path") },
|
|
67498
|
+
async (args5) => await stage([{ kind: "shopify.urlRedirect.delete", target: target3(args5, "path") }])
|
|
67499
|
+
);
|
|
67500
|
+
var campaignAdd = leaf(
|
|
67501
|
+
"shopify.change.campaign.add",
|
|
67502
|
+
{
|
|
67503
|
+
name: "add",
|
|
67504
|
+
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"
|
|
67505
|
+
},
|
|
67506
|
+
{
|
|
67507
|
+
platform: { type: "string", description: "google-ads | meta", required: false },
|
|
67508
|
+
account: { type: "string", description: "The ad account id", required: false },
|
|
67509
|
+
campaign: { type: "string", description: "The campaign id", required: false },
|
|
67510
|
+
"utm-campaign": { type: "string", description: "utm_campaign its links carry", required: false },
|
|
67511
|
+
"utm-source": { type: "string", description: "utm_source", required: false },
|
|
67512
|
+
"utm-medium": { type: "string", description: "utm_medium", required: false }
|
|
67513
|
+
},
|
|
67514
|
+
async (args5) => await stage([
|
|
67515
|
+
{
|
|
67516
|
+
kind: "shopify.marketingActivity.upsert",
|
|
67517
|
+
payload: {
|
|
67518
|
+
platform: args5.platform,
|
|
67519
|
+
accountId: args5.account,
|
|
67520
|
+
campaignId: args5.campaign,
|
|
67521
|
+
utm: { campaign: args5["utm-campaign"], source: args5["utm-source"], medium: args5["utm-medium"] }
|
|
67522
|
+
}
|
|
67523
|
+
}
|
|
67524
|
+
])
|
|
67525
|
+
);
|
|
67526
|
+
var campaignRemove = leaf(
|
|
67527
|
+
"shopify.change.campaign.remove",
|
|
67528
|
+
{
|
|
67529
|
+
name: "remove",
|
|
67530
|
+
description: "Take a Baker campaign out of Shopify Marketing. Example: baker shopify change campaign remove google-ads:3865083115:2101"
|
|
67531
|
+
},
|
|
67532
|
+
{ campaign: TARGET("<platform>:<account>:<campaign>") },
|
|
67533
|
+
async (args5) => await stage([{ kind: "shopify.marketingActivity.delete", target: target3(args5, "campaign") }])
|
|
67534
|
+
);
|
|
67535
|
+
var measurementReconnect = leaf(
|
|
67536
|
+
"shopify.change.measurement.reconnect",
|
|
67537
|
+
{
|
|
67538
|
+
name: "reconnect",
|
|
67539
|
+
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."
|
|
67540
|
+
},
|
|
67541
|
+
{},
|
|
67542
|
+
async () => await stage([{ kind: "shopify.webPixel.update" }])
|
|
67543
|
+
);
|
|
67544
|
+
var group = (name, description2, subCommands) => defineCommand211({ meta: { name, description: description2 }, subCommands });
|
|
67545
|
+
var changeCommand = defineCommand211({
|
|
67546
|
+
meta: {
|
|
67547
|
+
name: "change",
|
|
67548
|
+
description: `Stage a change to the connected store. Nothing changes until the user publishes the chat; every
|
|
67549
|
+
change can be put back with \`baker shopify undo\`. Prices and discounts need the user's yes first.
|
|
67550
|
+
|
|
67551
|
+
baker shopify change product update <product> --title \u2026 --seo-title \u2026 --add-tags a,b
|
|
67552
|
+
baker shopify change variant update <variantId> --sku \u2026 --barcode \u2026 --price \u2026
|
|
67553
|
+
baker shopify change field set product:<product> --namespace custom --key \u2026 --type \u2026 --value \u2026
|
|
67554
|
+
baker shopify change collection create --title \u2026 --products a,b
|
|
67555
|
+
baker shopify change discount create --code SPRING10 --percent 10 --ends <iso>
|
|
67556
|
+
baker shopify change redirect create --from /old --to /new
|
|
67557
|
+
baker shopify change campaign add --platform google-ads --account \u2026 --campaign \u2026
|
|
67558
|
+
baker shopify change measurement reconnect`
|
|
67559
|
+
},
|
|
67560
|
+
subCommands: {
|
|
67561
|
+
"signup-offer": group("signup-offer", "Stage or end a sign-up offer", { set: signupOfferSet, end: signupOfferEnd }),
|
|
67562
|
+
product: group("product", "Change a product's title, description, SEO, tags or type", { update: productUpdate }),
|
|
67563
|
+
variant: group("variant", "Change an option's SKU, barcode, weight or price", { update: variantUpdate }),
|
|
67564
|
+
field: group("field", "Set or remove a custom field", { set: fieldSet, remove: fieldRemove }),
|
|
67565
|
+
collection: group("collection", "Create, change, show, hide, fill or delete a collection", {
|
|
67566
|
+
create: collectionCreate,
|
|
67567
|
+
update: collectionUpdate,
|
|
67568
|
+
show: collectionVerb(
|
|
67569
|
+
"show",
|
|
67570
|
+
"shopify.collection.publish",
|
|
67571
|
+
"Show a collection on the online store. Example: baker shopify change collection show summer-boards"
|
|
67572
|
+
),
|
|
67573
|
+
hide: collectionVerb(
|
|
67574
|
+
"hide",
|
|
67575
|
+
"shopify.collection.unpublish",
|
|
67576
|
+
"Hide a collection from the online store. Example: baker shopify change collection hide summer-boards"
|
|
67577
|
+
),
|
|
67578
|
+
delete: collectionVerb(
|
|
67579
|
+
"delete",
|
|
67580
|
+
"shopify.collection.delete",
|
|
67581
|
+
"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"
|
|
67582
|
+
),
|
|
67583
|
+
add: membership(
|
|
67584
|
+
"add",
|
|
67585
|
+
"shopify.collection.addProducts",
|
|
67586
|
+
"Add products to a collection. Example: baker shopify change collection add summer-boards snowboard-a snowboard-b"
|
|
67587
|
+
),
|
|
67588
|
+
remove: membership(
|
|
67589
|
+
"remove",
|
|
67590
|
+
"shopify.collection.removeProducts",
|
|
67591
|
+
"Remove products from a collection. Example: baker shopify change collection remove summer-boards snowboard-a"
|
|
67592
|
+
)
|
|
67593
|
+
}),
|
|
67594
|
+
discount: group("discount", "Create, stop or reschedule a discount code (needs the user's yes)", {
|
|
67595
|
+
create: discountCreate,
|
|
67596
|
+
stop: discountStop,
|
|
67597
|
+
dates: discountDates
|
|
67598
|
+
}),
|
|
67599
|
+
redirect: group("redirect", "Create or remove a redirect", { create: redirectCreate, remove: redirectRemove }),
|
|
67600
|
+
campaign: group("campaign", "Show or remove a Baker campaign in Shopify Marketing", {
|
|
67601
|
+
add: campaignAdd,
|
|
67602
|
+
remove: campaignRemove
|
|
67603
|
+
}),
|
|
67604
|
+
measurement: group("measurement", "Reconnect Baker's measurement on the store", {
|
|
67605
|
+
reconnect: measurementReconnect
|
|
67606
|
+
})
|
|
67607
|
+
}
|
|
67608
|
+
});
|
|
67609
|
+
|
|
67610
|
+
// src/commands/shopify/changes.ts
|
|
67611
|
+
var changesCommand2 = leaf(
|
|
67612
|
+
"shopify.changes",
|
|
67613
|
+
{
|
|
67614
|
+
name: "changes",
|
|
67615
|
+
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)."
|
|
67616
|
+
},
|
|
67617
|
+
{
|
|
67618
|
+
limit: { type: "string", description: "How many, 1-100 (default 20)", required: false },
|
|
67619
|
+
chat: { type: "string", description: "Only one chat's changes", required: false }
|
|
67620
|
+
},
|
|
67621
|
+
async (args5) => {
|
|
67622
|
+
try {
|
|
67623
|
+
const data = await apiGet(
|
|
67624
|
+
"/api/shopify/changes",
|
|
67625
|
+
params({ limit: args5.limit, chatId: args5.chat })
|
|
67626
|
+
);
|
|
67627
|
+
writeJson({ ok: true, hints: changesHints(data), data });
|
|
67628
|
+
} catch (err) {
|
|
67629
|
+
failChange(err);
|
|
67630
|
+
}
|
|
67631
|
+
}
|
|
67632
|
+
);
|
|
67633
|
+
var undoCommand = leaf(
|
|
67634
|
+
"shopify.undo",
|
|
67635
|
+
{
|
|
67636
|
+
name: "undo",
|
|
67637
|
+
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]"
|
|
67638
|
+
},
|
|
67639
|
+
{ changeIds: { type: "positional", description: "changeIds from `baker shopify changes`", required: false } },
|
|
67640
|
+
async (args5) => {
|
|
67641
|
+
const changeIds = Array.isArray(args5._) ? args5._.filter((value) => typeof value === "string") : [];
|
|
67642
|
+
if (changeIds.length === 0) failValidation3("pass the changeIds to undo (see `baker shopify changes`)");
|
|
67643
|
+
try {
|
|
67644
|
+
const data = await apiPost("/api/shopify/undo", {
|
|
67645
|
+
chatId: requireChatId(),
|
|
67646
|
+
changeIds
|
|
67647
|
+
});
|
|
67648
|
+
emitStage(data);
|
|
67649
|
+
} catch (err) {
|
|
67650
|
+
failChange(err);
|
|
67651
|
+
}
|
|
67652
|
+
}
|
|
67653
|
+
);
|
|
67654
|
+
|
|
67655
|
+
// src/commands/shopify/draft.ts
|
|
67656
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
67657
|
+
function refOf(args5) {
|
|
67658
|
+
const [ref] = Array.isArray(args5._) ? args5._ : [];
|
|
67659
|
+
if (typeof ref !== "string" || ref === "")
|
|
67660
|
+
failValidation3("pass the staged change's ref (see `baker shopify draft list`)");
|
|
67661
|
+
return ref;
|
|
67662
|
+
}
|
|
67663
|
+
function listHints(data) {
|
|
67664
|
+
if (data.status === "none" || data.count === 0) return ["No store changes are staged on this chat."];
|
|
67665
|
+
if (data.status === "active") {
|
|
67666
|
+
return [
|
|
67667
|
+
"Staged only: these apply when the user publishes the chat. Correct one with `baker shopify draft amend <ref>`, drop one with `remove`."
|
|
67668
|
+
];
|
|
67669
|
+
}
|
|
67670
|
+
const failed = data.ops.filter((op) => op.result?.status === "failed" || op.result?.status === "skipped");
|
|
67671
|
+
return failed.length > 0 ? [`${failed.length} of ${data.count} changes did not go through \u2014 say which and why; never report them as made.`] : [];
|
|
67672
|
+
}
|
|
67673
|
+
var list2 = leaf(
|
|
67674
|
+
"shopify.draft.list",
|
|
67675
|
+
{
|
|
67676
|
+
name: "list",
|
|
67677
|
+
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."
|
|
67678
|
+
},
|
|
67679
|
+
{ chat: CHAT_READ_ARG },
|
|
67680
|
+
async (args5) => {
|
|
67681
|
+
try {
|
|
67682
|
+
const data = await apiPost("/api/shopify/draft/list", {
|
|
67683
|
+
chatId: resolveChatId(args5.chat)
|
|
67684
|
+
});
|
|
67685
|
+
writeJson({ ok: true, hints: listHints(data), data });
|
|
67686
|
+
} catch (err) {
|
|
67687
|
+
failChange(err);
|
|
67688
|
+
}
|
|
67689
|
+
}
|
|
67690
|
+
);
|
|
67691
|
+
var show = leaf(
|
|
67692
|
+
"shopify.draft.show",
|
|
67693
|
+
{
|
|
67694
|
+
name: "show",
|
|
67695
|
+
description: "One staged store change in full: what it sends and the store as it was read when it was staged (the before)."
|
|
67696
|
+
},
|
|
67697
|
+
{ ref: { type: "positional", description: "The staged change's ref", required: false }, chat: CHAT_READ_ARG },
|
|
67698
|
+
async (args5) => {
|
|
67699
|
+
try {
|
|
67700
|
+
const data = await apiPost("/api/shopify/draft/show", { chatId: resolveChatId(args5.chat), ref: refOf(args5) });
|
|
67701
|
+
writeJson({ ok: true, data });
|
|
67702
|
+
} catch (err) {
|
|
67703
|
+
failChange(err);
|
|
67704
|
+
}
|
|
67705
|
+
}
|
|
67706
|
+
);
|
|
67707
|
+
var amend = leaf(
|
|
67708
|
+
"shopify.draft.amend",
|
|
67709
|
+
{
|
|
67710
|
+
name: "amend",
|
|
67711
|
+
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.`
|
|
67712
|
+
},
|
|
67713
|
+
{
|
|
67714
|
+
ref: { type: "positional", description: "The staged change's ref", required: false },
|
|
67715
|
+
patch: { type: "string", description: "Inline JSON patch", required: false },
|
|
67716
|
+
file: { type: "string", description: "A JSON file with the patch", required: false }
|
|
67717
|
+
},
|
|
67718
|
+
async (args5) => {
|
|
67719
|
+
try {
|
|
67720
|
+
const data = await apiPost("/api/shopify/draft/amend", {
|
|
67721
|
+
chatId: requireChatId(),
|
|
67722
|
+
ref: refOf(args5),
|
|
67723
|
+
patch: loadJsonArg(args5, "patch")
|
|
67724
|
+
});
|
|
67725
|
+
emitStage(data);
|
|
67726
|
+
} catch (err) {
|
|
67727
|
+
failChange(err);
|
|
67728
|
+
}
|
|
67729
|
+
}
|
|
67730
|
+
);
|
|
67731
|
+
var remove = leaf(
|
|
67732
|
+
"shopify.draft.remove",
|
|
67733
|
+
{
|
|
67734
|
+
name: "remove",
|
|
67735
|
+
description: "Drop one staged store change, and any change that needs it (a new collection's show)."
|
|
67736
|
+
},
|
|
67737
|
+
{ ref: { type: "positional", description: "The staged change's ref", required: false } },
|
|
67738
|
+
async (args5) => {
|
|
67739
|
+
try {
|
|
67740
|
+
writeJson({
|
|
67741
|
+
ok: true,
|
|
67742
|
+
data: await apiPost("/api/shopify/draft/remove", { chatId: requireChatId(), ref: refOf(args5) })
|
|
67743
|
+
});
|
|
67744
|
+
} catch (err) {
|
|
67745
|
+
failChange(err);
|
|
67746
|
+
}
|
|
67747
|
+
}
|
|
67748
|
+
);
|
|
67749
|
+
var clear = leaf(
|
|
67750
|
+
"shopify.draft.clear",
|
|
67751
|
+
{ name: "clear", description: "Drop every store change staged on this chat." },
|
|
67752
|
+
{},
|
|
67753
|
+
async () => {
|
|
67754
|
+
try {
|
|
67755
|
+
writeJson({ ok: true, data: await apiPost("/api/shopify/draft/clear", { chatId: requireChatId() }) });
|
|
67756
|
+
} catch (err) {
|
|
67757
|
+
failChange(err);
|
|
67758
|
+
}
|
|
67759
|
+
}
|
|
67760
|
+
);
|
|
67761
|
+
var draftCommand5 = defineCommand212({
|
|
67762
|
+
meta: { name: "draft", description: "List, show, amend, remove or clear the store changes staged on this chat" },
|
|
67763
|
+
subCommands: { list: list2, show, amend, remove, clear }
|
|
67764
|
+
});
|
|
67765
|
+
|
|
67766
|
+
// src/commands/shopify/promotions.ts
|
|
67767
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
67768
|
+
|
|
66441
67769
|
// src/commands/shopify/landingLinks.ts
|
|
66442
67770
|
import { readdir as readdir16, readFile as readFile33, stat as stat11 } from "fs/promises";
|
|
66443
67771
|
import path47 from "path";
|
|
67772
|
+
import { parse } from "@astrojs/compiler/sync";
|
|
66444
67773
|
var PAGES_MAX = 300;
|
|
66445
67774
|
var FILE_BYTES_MAX = 256 * 1024;
|
|
66446
67775
|
function escaped(text2) {
|
|
66447
67776
|
return text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
66448
67777
|
}
|
|
66449
|
-
|
|
67778
|
+
var BUY_COMPONENTS = /* @__PURE__ */ new Set(["ShopifyProduct", "ShopifyBuyButton"]);
|
|
67779
|
+
var STRING_LITERAL = /^\s*(["'`])([^"'`]*)\1\s*$/;
|
|
67780
|
+
var ITEM_PRODUCT = /\bproduct\s*:\s*(["'`])([^"'`]*)\1/g;
|
|
67781
|
+
function namedBy(attribute) {
|
|
67782
|
+
if (attribute.name === "product") {
|
|
67783
|
+
if (attribute.kind === "quoted" || attribute.kind === "template-literal") return [attribute.value];
|
|
67784
|
+
if (attribute.kind === "expression") return [STRING_LITERAL.exec(attribute.value)?.[2] ?? ""];
|
|
67785
|
+
}
|
|
67786
|
+
if (attribute.name === "items" && attribute.kind === "expression") {
|
|
67787
|
+
return [...attribute.value.matchAll(ITEM_PRODUCT)].map((match) => match[2] ?? "");
|
|
67788
|
+
}
|
|
67789
|
+
return [];
|
|
67790
|
+
}
|
|
67791
|
+
function componentProducts(node, into) {
|
|
67792
|
+
if (node.type === "component" && BUY_COMPONENTS.has(node.name)) {
|
|
67793
|
+
for (const attribute of node.attributes) into.push(...namedBy(attribute));
|
|
67794
|
+
}
|
|
67795
|
+
if ("children" in node) for (const child of node.children) componentProducts(child, into);
|
|
67796
|
+
return into;
|
|
67797
|
+
}
|
|
67798
|
+
function buyComponentProducts(file) {
|
|
67799
|
+
if (!file.path.endsWith(".astro")) return [];
|
|
67800
|
+
try {
|
|
67801
|
+
return componentProducts(parse(file.text, void 0).ast, []);
|
|
67802
|
+
} catch {
|
|
67803
|
+
return [];
|
|
67804
|
+
}
|
|
67805
|
+
}
|
|
67806
|
+
function namesProduct(file, keys) {
|
|
67807
|
+
const wanted = new Set([keys.handle.toLowerCase(), ...keys.productId ? [keys.productId] : []].filter(Boolean));
|
|
67808
|
+
return buyComponentProducts(file).some((named) => wanted.has(named.trim().toLowerCase()));
|
|
67809
|
+
}
|
|
67810
|
+
function evidenceIn(file, keys) {
|
|
67811
|
+
const { text: text2 } = file;
|
|
66450
67812
|
const evidence = [];
|
|
66451
67813
|
if (keys.buyUrls.some((url) => url && text2.includes(url))) evidence.push("buy_link");
|
|
66452
67814
|
const page = new RegExp(`/products/${escaped(keys.handle)}(?![A-Za-z0-9_-])`, "i");
|
|
@@ -66455,24 +67817,25 @@ function evidenceIn(text2, keys) {
|
|
|
66455
67817
|
(id) => new RegExp(`(?:/cart/(?:\\d+:\\d+,)*${id}:|variant=${id}(?!\\d))`).test(text2)
|
|
66456
67818
|
);
|
|
66457
67819
|
if (option) evidence.push("variant_id");
|
|
67820
|
+
if (namesProduct(file, keys)) evidence.push("buy_button");
|
|
66458
67821
|
return evidence;
|
|
66459
67822
|
}
|
|
66460
67823
|
function landingLinksOf(pages, keys) {
|
|
66461
67824
|
const bySlug = /* @__PURE__ */ new Map();
|
|
66462
67825
|
for (const page of pages) {
|
|
66463
|
-
const found = new Set(page.files.flatMap((file) => evidenceIn(file
|
|
67826
|
+
const found = new Set(page.files.flatMap((file) => evidenceIn(file, keys)));
|
|
66464
67827
|
if (found.size === 0) continue;
|
|
66465
67828
|
const slug = page.slug.replace(/--\d+$/, "");
|
|
66466
67829
|
const held = bySlug.get(slug) ?? /* @__PURE__ */ new Set();
|
|
66467
67830
|
for (const evidence of found) held.add(evidence);
|
|
66468
67831
|
bySlug.set(slug, held);
|
|
66469
67832
|
}
|
|
66470
|
-
const order = ["buy_link", "product_page", "variant_id"];
|
|
67833
|
+
const order = ["buy_link", "product_page", "variant_id", "buy_button"];
|
|
66471
67834
|
return [...bySlug].map(([slug, evidence]) => ({ slug, evidence: order.filter((entry) => evidence.has(entry)) }));
|
|
66472
67835
|
}
|
|
66473
|
-
async function isDir4(
|
|
67836
|
+
async function isDir4(target4) {
|
|
66474
67837
|
try {
|
|
66475
|
-
return (await stat11(
|
|
67838
|
+
return (await stat11(target4)).isDirectory();
|
|
66476
67839
|
} catch {
|
|
66477
67840
|
return false;
|
|
66478
67841
|
}
|
|
@@ -66510,8 +67873,8 @@ function plural(count2, one, many = `${one}s`) {
|
|
|
66510
67873
|
}
|
|
66511
67874
|
function pauseCommand2(ad) {
|
|
66512
67875
|
if (ad.platform === "meta") return `\`baker ads meta ads pause ${ad.id ?? "<id>"}\``;
|
|
66513
|
-
const
|
|
66514
|
-
return ad.level === "asset_group" ? `\`baker ads google asset-groups update ${
|
|
67876
|
+
const target4 = `${ad.resource ?? "<resource>"} --customer-id ${ad.account_id ?? "<account_id>"}`;
|
|
67877
|
+
return ad.level === "asset_group" ? `\`baker ads google asset-groups update ${target4} --status PAUSED\`` : `\`baker ads google ads pause ${target4}\``;
|
|
66515
67878
|
}
|
|
66516
67879
|
function pauseHint(answer) {
|
|
66517
67880
|
if (answer.product.stock === "in_stock" || answer.ads.length === 0) return null;
|
|
@@ -66520,8 +67883,7 @@ function pauseHint(answer) {
|
|
|
66520
67883
|
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.`;
|
|
66521
67884
|
}
|
|
66522
67885
|
const one = active.length === 1;
|
|
66523
|
-
|
|
66524
|
-
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}`;
|
|
67886
|
+
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.`;
|
|
66525
67887
|
}
|
|
66526
67888
|
function promotionHints(answer, scan) {
|
|
66527
67889
|
const hints2 = [];
|
|
@@ -66555,7 +67917,7 @@ function promotionHints(answer, scan) {
|
|
|
66555
67917
|
}
|
|
66556
67918
|
if (!answer.remembered && answer.ads.length > 0) {
|
|
66557
67919
|
hints2.push(
|
|
66558
|
-
"This read was
|
|
67920
|
+
"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."
|
|
66559
67921
|
);
|
|
66560
67922
|
}
|
|
66561
67923
|
return hints2;
|
|
@@ -66589,8 +67951,8 @@ var META_GROUP = {
|
|
|
66589
67951
|
};
|
|
66590
67952
|
function resumeCommand2(hold) {
|
|
66591
67953
|
if (hold.platform === "meta") return `baker ads meta ${META_GROUP[hold.level]} resume ${hold.entity_id}`;
|
|
66592
|
-
const
|
|
66593
|
-
return hold.level === "asset_group" ? `baker ads google asset-groups update ${
|
|
67954
|
+
const target4 = `${hold.entity_id} --customer-id ${hold.account_id}`;
|
|
67955
|
+
return hold.level === "asset_group" ? `baker ads google asset-groups update ${target4} --status ENABLED` : `baker ads google ${GOOGLE_GROUP[hold.level]} resume ${target4}`;
|
|
66594
67956
|
}
|
|
66595
67957
|
function quoted(title, fallback) {
|
|
66596
67958
|
return title ? `\u201C${title}\u201D` : fallback;
|
|
@@ -66691,7 +68053,12 @@ registerSchema({
|
|
|
66691
68053
|
full: fullArg
|
|
66692
68054
|
}
|
|
66693
68055
|
});
|
|
66694
|
-
|
|
68056
|
+
function promotionsShown(answer, full) {
|
|
68057
|
+
if (full) return answer;
|
|
68058
|
+
const { remembered: _remembered, ...shown } = answer;
|
|
68059
|
+
return shown;
|
|
68060
|
+
}
|
|
68061
|
+
var promotionsCommand = defineCommand213({
|
|
66695
68062
|
meta: {
|
|
66696
68063
|
name: "promotions",
|
|
66697
68064
|
description: "What advertises one product: ads that lead to it, landings that link to it, Shopping that shows it. Example: baker shopify promotions 10310413942969"
|
|
@@ -66707,8 +68074,8 @@ var promotionsCommand = defineCommand210({
|
|
|
66707
68074
|
},
|
|
66708
68075
|
run: async ({ args: args5 }) => {
|
|
66709
68076
|
try {
|
|
66710
|
-
const
|
|
66711
|
-
if (
|
|
68077
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
68078
|
+
if (positionals2.length > 1) {
|
|
66712
68079
|
throw new ApiError("VALIDATION_ERROR", "product: Pass one product id, handle or product link.");
|
|
66713
68080
|
}
|
|
66714
68081
|
const { product, store } = await apiGet(
|
|
@@ -66718,6 +68085,7 @@ var promotionsCommand = defineCommand210({
|
|
|
66718
68085
|
const scan = await readWorkspacePages(process.cwd());
|
|
66719
68086
|
const linked = scan ? landingLinksOf(scan.pages, {
|
|
66720
68087
|
handle: product.handle,
|
|
68088
|
+
productId: product.productId,
|
|
66721
68089
|
variantIds: product.variants.map((variant) => variant.variantId),
|
|
66722
68090
|
buyUrls: product.variants.flatMap((variant) => variant.buyUrl ? [variant.buyUrl] : [])
|
|
66723
68091
|
}) : void 0;
|
|
@@ -66727,7 +68095,7 @@ var promotionsCommand = defineCommand210({
|
|
|
66727
68095
|
scanned: scan !== null,
|
|
66728
68096
|
...args5.full ? { full: true } : {}
|
|
66729
68097
|
});
|
|
66730
|
-
emit2(answer, { store }, [
|
|
68098
|
+
emit2(promotionsShown(answer, args5.full === true), { store }, [
|
|
66731
68099
|
...storeStateHints(store),
|
|
66732
68100
|
...promotionHints(answer, { scanned: scan !== null, skippedPages: scan?.skipped ?? 0 })
|
|
66733
68101
|
]);
|
|
@@ -66736,7 +68104,7 @@ var promotionsCommand = defineCommand210({
|
|
|
66736
68104
|
}
|
|
66737
68105
|
}
|
|
66738
68106
|
});
|
|
66739
|
-
var stockHoldsCommand =
|
|
68107
|
+
var stockHoldsCommand = defineCommand213({
|
|
66740
68108
|
meta: {
|
|
66741
68109
|
name: "stock-holds",
|
|
66742
68110
|
description: "The ads Baker paused because a product ran out, and whether each may be resumed now. Example: baker shopify stock-holds --product 10310413942969"
|
|
@@ -66763,10 +68131,121 @@ var stockHoldsCommand = defineCommand210({
|
|
|
66763
68131
|
}
|
|
66764
68132
|
});
|
|
66765
68133
|
|
|
68134
|
+
// ../api/src/shopify/signups.ts
|
|
68135
|
+
import { z as z53 } from "zod";
|
|
68136
|
+
var SIGNUP_CODE_PATTERN = /^[A-Z0-9]{2,12}-[0-9A-HJKMNP-TV-Z]{8}$/;
|
|
68137
|
+
var SIGNUP_STATES = [
|
|
68138
|
+
"waiting",
|
|
68139
|
+
"ready",
|
|
68140
|
+
"used",
|
|
68141
|
+
"expired",
|
|
68142
|
+
"already",
|
|
68143
|
+
"ended",
|
|
68144
|
+
"none",
|
|
68145
|
+
"unavailable"
|
|
68146
|
+
];
|
|
68147
|
+
var CODE_STATES = /* @__PURE__ */ new Set(["ready", "used", "expired"]);
|
|
68148
|
+
var shopifySignupReplySchema = z53.object({
|
|
68149
|
+
state: z53.enum(SIGNUP_STATES),
|
|
68150
|
+
code: z53.string().regex(SIGNUP_CODE_PATTERN).optional(),
|
|
68151
|
+
endsAt: z53.string().min(1).max(40).optional()
|
|
68152
|
+
}).strict().refine(
|
|
68153
|
+
(reply) => CODE_STATES.has(reply.state) ? reply.code !== void 0 && reply.endsAt !== void 0 : true,
|
|
68154
|
+
"a code state carries the code and when it ends"
|
|
68155
|
+
).refine(
|
|
68156
|
+
(reply) => CODE_STATES.has(reply.state) ? true : reply.code === void 0 && reply.endsAt === void 0,
|
|
68157
|
+
"only the browser the code was given to is told it"
|
|
68158
|
+
);
|
|
68159
|
+
var shopifySignupResponseSchema = z53.union([
|
|
68160
|
+
z53.object({ ok: z53.literal(true), signup: shopifySignupReplySchema }).passthrough(),
|
|
68161
|
+
z53.object({ error: z53.string(), signup: shopifySignupReplySchema }).passthrough()
|
|
68162
|
+
]);
|
|
68163
|
+
var signupOfferStatusSchema = z53.enum(["active", "ended", "staged"]);
|
|
68164
|
+
var shopifySignupOfferViewSchema = z53.object({
|
|
68165
|
+
handle: z53.string(),
|
|
68166
|
+
name: z53.string(),
|
|
68167
|
+
/** "10% off everything, each code valid 14 days, at most 1,000 codes". */
|
|
68168
|
+
summary: z53.string(),
|
|
68169
|
+
status: signupOfferStatusSchema,
|
|
68170
|
+
validForDays: z53.number(),
|
|
68171
|
+
endsAt: z53.string().optional(),
|
|
68172
|
+
maxCodes: z53.number().optional(),
|
|
68173
|
+
codesGiven: z53.number()
|
|
68174
|
+
});
|
|
68175
|
+
var shopifySignupOffersResponseSchema = z53.object({
|
|
68176
|
+
/** The company has a store connection Baker can use (connected, not waiting on a reconnect). */
|
|
68177
|
+
connected: z53.boolean(),
|
|
68178
|
+
/** The store allows Baker to add customers (sign-ups work). */
|
|
68179
|
+
canAddCustomers: z53.boolean(),
|
|
68180
|
+
/** The store allows Baker to make discount codes (offers give codes). */
|
|
68181
|
+
canGiveCodes: z53.boolean(),
|
|
68182
|
+
offers: z53.array(shopifySignupOfferViewSchema),
|
|
68183
|
+
/** Sign-ups the store didn't take in the last 7 days: for a missing permission, and for anything else. */
|
|
68184
|
+
refusedLast7Days: z53.object({ permission: z53.number(), other: z53.number() })
|
|
68185
|
+
});
|
|
68186
|
+
|
|
68187
|
+
// src/commands/shopify/signupOffers.ts
|
|
68188
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
68189
|
+
var description = "Start here for landing sign-ups: published and this chat's staged offers, codes given and store permissions. Example: baker shopify signup-offers. Forms name an offer handle; terms are staged with baker shopify change signup-offer set.";
|
|
68190
|
+
registerSchema({ command: "shopify.signupOffers", description, args: {} });
|
|
68191
|
+
var signupOffersCommand = defineCommand214({
|
|
68192
|
+
meta: { name: "signup-offers", description },
|
|
68193
|
+
async run() {
|
|
68194
|
+
try {
|
|
68195
|
+
const data = shopifySignupOffersResponseSchema.parse(
|
|
68196
|
+
await apiGet("/api/shopify/signup-offers", params({ chatId: optionalChatId() }))
|
|
68197
|
+
);
|
|
68198
|
+
const hints2 = [];
|
|
68199
|
+
if (!data.canAddCustomers)
|
|
68200
|
+
hints2.push(
|
|
68201
|
+
'Sign-ups cannot be added to the store yet: call request_connection with { platform: "shopify", reason: "Add sign-ups from your landing" }. Keep building the page; the Form works once allowed.'
|
|
68202
|
+
);
|
|
68203
|
+
if (!data.canGiveCodes)
|
|
68204
|
+
hints2.push(
|
|
68205
|
+
"Codes need the store to allow discounts: use request_connection for Shopify and keep building the page."
|
|
68206
|
+
);
|
|
68207
|
+
if (data.offers.some((offer) => offer.status === "ended"))
|
|
68208
|
+
hints2.push(
|
|
68209
|
+
"Forms naming ended offers still add customers but give no code: stage a new offer or remove offer from the Form."
|
|
68210
|
+
);
|
|
68211
|
+
if (data.offers.length === 0)
|
|
68212
|
+
hints2.push(
|
|
68213
|
+
"No sign-up offer exists yet. Omit offer for sign-ups without a code, or stage one after the user approves its terms."
|
|
68214
|
+
);
|
|
68215
|
+
writeJson({ ok: true, hints: hints2, data });
|
|
68216
|
+
} catch (error) {
|
|
68217
|
+
fail9(error);
|
|
68218
|
+
}
|
|
68219
|
+
}
|
|
68220
|
+
});
|
|
68221
|
+
|
|
68222
|
+
// src/commands/shopify/tracking.ts
|
|
68223
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
68224
|
+
var audit = leaf(
|
|
68225
|
+
"shopify.tracking.audit",
|
|
68226
|
+
{
|
|
68227
|
+
name: "audit",
|
|
68228
|
+
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."
|
|
68229
|
+
},
|
|
68230
|
+
{ full: { type: "boolean", description: "Add the facts behind each check", required: false } },
|
|
68231
|
+
async (args5) => {
|
|
68232
|
+
try {
|
|
68233
|
+
const data = await apiPost("/api/shopify/tracking/audit", { full: args5.full === true });
|
|
68234
|
+
writeJson({ ok: true, hints: auditHints(data), data });
|
|
68235
|
+
} catch (err) {
|
|
68236
|
+
fail9(err);
|
|
68237
|
+
}
|
|
68238
|
+
}
|
|
68239
|
+
);
|
|
68240
|
+
var trackingCommand2 = defineCommand215({
|
|
68241
|
+
meta: { name: "tracking", description: "Check how the store is measured: baker shopify tracking audit" },
|
|
68242
|
+
subCommands: { audit }
|
|
68243
|
+
});
|
|
68244
|
+
|
|
66766
68245
|
// src/commands/shopify/index.ts
|
|
66767
68246
|
registerSchema({
|
|
66768
68247
|
command: "shopify.store",
|
|
66769
|
-
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.',
|
|
68248
|
+
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`).',
|
|
66770
68249
|
args: {
|
|
66771
68250
|
full: {
|
|
66772
68251
|
...fullArg,
|
|
@@ -66801,7 +68280,7 @@ registerSchema({
|
|
|
66801
68280
|
});
|
|
66802
68281
|
registerSchema({
|
|
66803
68282
|
command: "shopify.product",
|
|
66804
|
-
description: "One product of the connected store \u2014 accepts its id, its handle, a link to it on the store, in Baker or in Shopify admin. Returns its options with price, stock and `buyUrl` (
|
|
68283
|
+
description: "One product of the connected store \u2014 accepts its id, its handle, a link to it on the store, in Baker or in Shopify admin. Returns its options with price, stock and `buyUrl` (each option's buy link for ads, emails and messages; on a landing use `<ShopifyProduct>` instead \u2014 never build a Shopify link yourself, never use `storeUrl` for it), prices by country, the options out of stock, its collections, its photos' library imageIds to place on a landing (`baker images download <imageIds> --out src/pages/<page>/_images/`) or pass to a creative, its videos' playbackIds (`<Video playbackId=\u2026/>`), and `contentSummary`: what else Baker keeps about it. Start here for a landing from a product: add `--content` for the formatted description, every custom field by its name (a size chart, care instructions), the rating, subscriptions and translations; `--field <name>` returns one field whole. `--out-of-stock` lists only the options out of stock.",
|
|
66805
68284
|
args: {
|
|
66806
68285
|
ref: { type: "positional", description: "Product id, handle, or a link to the product", required: true },
|
|
66807
68286
|
"variants-cursor": {
|
|
@@ -66891,7 +68370,7 @@ registerSchema({
|
|
|
66891
68370
|
}
|
|
66892
68371
|
}
|
|
66893
68372
|
});
|
|
66894
|
-
var salesCommand =
|
|
68373
|
+
var salesCommand = defineCommand216({
|
|
66895
68374
|
meta: {
|
|
66896
68375
|
name: "sales",
|
|
66897
68376
|
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"
|
|
@@ -66929,7 +68408,7 @@ var salesCommand = defineCommand211({
|
|
|
66929
68408
|
}
|
|
66930
68409
|
}
|
|
66931
68410
|
});
|
|
66932
|
-
var storeCommand =
|
|
68411
|
+
var storeCommand = defineCommand216({
|
|
66933
68412
|
meta: {
|
|
66934
68413
|
name: "store",
|
|
66935
68414
|
description: "The connected Shopify store: currency, countries, how many products, what is out of stock. Example: baker shopify store"
|
|
@@ -66940,13 +68419,14 @@ var storeCommand = defineCommand211({
|
|
|
66940
68419
|
run: async ({ args: args5 }) => {
|
|
66941
68420
|
try {
|
|
66942
68421
|
const answer = await apiGet("/api/shopify/store", params({ full: args5.full }));
|
|
66943
|
-
|
|
68422
|
+
const data = answer.canChange ? { ...answer.summary, canChange: answer.canChange } : answer.summary;
|
|
68423
|
+
emit2(data, { store: answer.store }, [...storeStateHints(answer.store), ...storeHints(answer.summary)]);
|
|
66944
68424
|
} catch (err) {
|
|
66945
68425
|
fail9(err);
|
|
66946
68426
|
}
|
|
66947
68427
|
}
|
|
66948
68428
|
});
|
|
66949
|
-
var productsCommand =
|
|
68429
|
+
var productsCommand = defineCommand216({
|
|
66950
68430
|
meta: {
|
|
66951
68431
|
name: "products",
|
|
66952
68432
|
description: 'What the store sells, with price and stock. Example: baker shopify products --search "snowboard" --stock out_of_stock'
|
|
@@ -66992,7 +68472,7 @@ var productsCommand = defineCommand211({
|
|
|
66992
68472
|
}
|
|
66993
68473
|
}
|
|
66994
68474
|
});
|
|
66995
|
-
var productCommand =
|
|
68475
|
+
var productCommand = defineCommand216({
|
|
66996
68476
|
meta: {
|
|
66997
68477
|
name: "product",
|
|
66998
68478
|
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"
|
|
@@ -67026,8 +68506,8 @@ var productCommand = defineCommand211({
|
|
|
67026
68506
|
},
|
|
67027
68507
|
run: async ({ args: args5 }) => {
|
|
67028
68508
|
try {
|
|
67029
|
-
const
|
|
67030
|
-
if (
|
|
68509
|
+
const positionals2 = Array.isArray(args5._) ? args5._ : [];
|
|
68510
|
+
if (positionals2.length > 1) {
|
|
67031
68511
|
throw new ApiError(
|
|
67032
68512
|
"VALIDATION_ERROR",
|
|
67033
68513
|
"ref: Pass one product id, handle or product link \u2014 quote a link, and search by words with `baker shopify products --search`."
|
|
@@ -67055,7 +68535,7 @@ var productCommand = defineCommand211({
|
|
|
67055
68535
|
}
|
|
67056
68536
|
}
|
|
67057
68537
|
});
|
|
67058
|
-
var collectionsCommand =
|
|
68538
|
+
var collectionsCommand = defineCommand216({
|
|
67059
68539
|
meta: {
|
|
67060
68540
|
name: "collections",
|
|
67061
68541
|
description: "The store's collections, with the handles --collection takes. Example: baker shopify collections --full"
|
|
@@ -67080,7 +68560,7 @@ var collectionsCommand = defineCommand211({
|
|
|
67080
68560
|
}
|
|
67081
68561
|
}
|
|
67082
68562
|
});
|
|
67083
|
-
var stockCommand2 =
|
|
68563
|
+
var stockCommand2 = defineCommand216({
|
|
67084
68564
|
meta: {
|
|
67085
68565
|
name: "stock",
|
|
67086
68566
|
description: "Every product with options out of stock, naming them. Example: baker shopify stock"
|
|
@@ -67104,12 +68584,12 @@ var stockCommand2 = defineCommand211({
|
|
|
67104
68584
|
}
|
|
67105
68585
|
}
|
|
67106
68586
|
});
|
|
67107
|
-
var shopifyCommand =
|
|
68587
|
+
var shopifyCommand = defineCommand216({
|
|
67108
68588
|
meta: {
|
|
67109
68589
|
name: "shopify",
|
|
67110
68590
|
description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections,
|
|
67111
|
-
product photos, what it sold, who buys, where and what, and what advertises each product
|
|
67112
|
-
|
|
68591
|
+
product photos, what it sold, who buys, where and what, and what advertises each product \u2014 and stage
|
|
68592
|
+
changes to it (\`change\`), applied when the user publishes the chat and undone with \`undo\`.
|
|
67113
68593
|
|
|
67114
68594
|
Examples:
|
|
67115
68595
|
baker shopify store # currency, countries, how many products, what is out of stock
|
|
@@ -67133,17 +68613,22 @@ Examples:
|
|
|
67133
68613
|
baker shopify cohorts --months 12 # buyers by first-order month: who came back
|
|
67134
68614
|
baker shopify promotions <product> # what advertises it: ads, landings, Shopping (read before pausing)
|
|
67135
68615
|
baker shopify stock-holds --product <product> # what Baker paused because it ran out: what to resume, what to tell the user
|
|
68616
|
+
baker shopify change product update <product> --title "\u2026" # stage a store change (product|variant|field|collection|discount|redirect|campaign|measurement)
|
|
68617
|
+
baker shopify draft list # the store changes staged on this chat
|
|
68618
|
+
baker shopify changes # what Baker changed in the store; baker shopify undo <changeId> puts one back
|
|
68619
|
+
baker shopify tracking audit # is the store measured right? (reads only)
|
|
67136
68620
|
|
|
67137
68621
|
Product photos are already in the image library: place them by imageId
|
|
67138
68622
|
(baker images download <imageIds> --out src/pages/<page>/_images/), never by a cdn.shopify.com link.
|
|
67139
68623
|
Product videos are in the video library: place them with <Video playbackId="\u2026" />.
|
|
67140
|
-
|
|
67141
|
-
|
|
68624
|
+
On a landing, the buy button is <ShopifyProduct product="\u2026"/> \u2014 never a buyUrl or a Shopify link
|
|
68625
|
+
written by hand. buyUrl is for ads, emails and messages; never use storeUrl (a page to look at) for it.
|
|
67142
68626
|
NO_SHOPIFY_CONNECTION means no store is connected: follow error.fix. SHOPIFY_NOT_AVAILABLE means it cannot be
|
|
67143
68627
|
connected here yet: carry on without it.
|
|
67144
68628
|
Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
67145
68629
|
},
|
|
67146
68630
|
subCommands: {
|
|
68631
|
+
"signup-offers": signupOffersCommand,
|
|
67147
68632
|
store: storeCommand,
|
|
67148
68633
|
products: productsCommand,
|
|
67149
68634
|
product: productCommand,
|
|
@@ -67157,15 +68642,20 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
|
67157
68642
|
cohorts: cohortsCommand,
|
|
67158
68643
|
segments: segmentsCommand,
|
|
67159
68644
|
promotions: promotionsCommand,
|
|
67160
|
-
"stock-holds": stockHoldsCommand
|
|
68645
|
+
"stock-holds": stockHoldsCommand,
|
|
68646
|
+
change: changeCommand,
|
|
68647
|
+
draft: draftCommand5,
|
|
68648
|
+
changes: changesCommand2,
|
|
68649
|
+
undo: undoCommand,
|
|
68650
|
+
tracking: trackingCommand2
|
|
67161
68651
|
}
|
|
67162
68652
|
});
|
|
67163
68653
|
|
|
67164
68654
|
// src/commands/studio/index.ts
|
|
67165
|
-
import { defineCommand as
|
|
68655
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
67166
68656
|
|
|
67167
68657
|
// src/commands/studio/animate.ts
|
|
67168
|
-
import { defineCommand as
|
|
68658
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
67169
68659
|
|
|
67170
68660
|
// src/commands/studio/spokenPace.ts
|
|
67171
68661
|
var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
|
|
@@ -67678,7 +69168,7 @@ async function adByHandHintFor(body) {
|
|
|
67678
69168
|
return null;
|
|
67679
69169
|
}
|
|
67680
69170
|
}
|
|
67681
|
-
var animateCommand =
|
|
69171
|
+
var animateCommand = defineCommand217({
|
|
67682
69172
|
meta: {
|
|
67683
69173
|
name: "animate",
|
|
67684
69174
|
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"
|
|
@@ -67803,7 +69293,7 @@ var animateCommand = defineCommand212({
|
|
|
67803
69293
|
});
|
|
67804
69294
|
|
|
67805
69295
|
// src/commands/studio/generate.ts
|
|
67806
|
-
import { defineCommand as
|
|
69296
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
67807
69297
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
67808
69298
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
67809
69299
|
registerSchema({
|
|
@@ -67939,7 +69429,7 @@ function buildGenerateBody(args5, prompt) {
|
|
|
67939
69429
|
}
|
|
67940
69430
|
return body;
|
|
67941
69431
|
}
|
|
67942
|
-
var generateCommand =
|
|
69432
|
+
var generateCommand = defineCommand218({
|
|
67943
69433
|
meta: {
|
|
67944
69434
|
name: "generate",
|
|
67945
69435
|
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]]'"
|
|
@@ -68022,7 +69512,7 @@ var generateCommand = defineCommand213({
|
|
|
68022
69512
|
});
|
|
68023
69513
|
|
|
68024
69514
|
// src/commands/studio/get.ts
|
|
68025
|
-
import { defineCommand as
|
|
69515
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
68026
69516
|
registerSchema({
|
|
68027
69517
|
command: "studio.get",
|
|
68028
69518
|
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.",
|
|
@@ -68031,7 +69521,7 @@ registerSchema({
|
|
|
68031
69521
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
68032
69522
|
}
|
|
68033
69523
|
});
|
|
68034
|
-
var getCommand5 =
|
|
69524
|
+
var getCommand5 = defineCommand219({
|
|
68035
69525
|
meta: {
|
|
68036
69526
|
name: "get",
|
|
68037
69527
|
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"
|
|
@@ -68060,7 +69550,7 @@ var getCommand5 = defineCommand214({
|
|
|
68060
69550
|
});
|
|
68061
69551
|
|
|
68062
69552
|
// src/commands/studio/improve.ts
|
|
68063
|
-
import { defineCommand as
|
|
69553
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
68064
69554
|
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.";
|
|
68065
69555
|
registerSchema({
|
|
68066
69556
|
command: "studio.improve",
|
|
@@ -68085,7 +69575,7 @@ registerSchema({
|
|
|
68085
69575
|
}
|
|
68086
69576
|
}
|
|
68087
69577
|
});
|
|
68088
|
-
var improveCommand =
|
|
69578
|
+
var improveCommand = defineCommand220({
|
|
68089
69579
|
meta: {
|
|
68090
69580
|
name: "improve",
|
|
68091
69581
|
description: `${DESCRIPTION2}
|
|
@@ -68129,7 +69619,7 @@ Examples:
|
|
|
68129
69619
|
});
|
|
68130
69620
|
|
|
68131
69621
|
// src/commands/studio/keep.ts
|
|
68132
|
-
import { defineCommand as
|
|
69622
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
68133
69623
|
registerSchema({
|
|
68134
69624
|
command: "studio.keep",
|
|
68135
69625
|
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.",
|
|
@@ -68139,7 +69629,7 @@ registerSchema({
|
|
|
68139
69629
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
68140
69630
|
}
|
|
68141
69631
|
});
|
|
68142
|
-
var keepCommand =
|
|
69632
|
+
var keepCommand = defineCommand221({
|
|
68143
69633
|
meta: {
|
|
68144
69634
|
name: "keep",
|
|
68145
69635
|
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"
|
|
@@ -68190,7 +69680,7 @@ var keepCommand = defineCommand216({
|
|
|
68190
69680
|
});
|
|
68191
69681
|
|
|
68192
69682
|
// src/commands/studio/list.ts
|
|
68193
|
-
import { defineCommand as
|
|
69683
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
68194
69684
|
registerSchema({
|
|
68195
69685
|
command: "studio.list",
|
|
68196
69686
|
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.",
|
|
@@ -68201,7 +69691,7 @@ registerSchema({
|
|
|
68201
69691
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
68202
69692
|
}
|
|
68203
69693
|
});
|
|
68204
|
-
var listCommand18 =
|
|
69694
|
+
var listCommand18 = defineCommand222({
|
|
68205
69695
|
meta: {
|
|
68206
69696
|
name: "list",
|
|
68207
69697
|
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"
|
|
@@ -68235,7 +69725,7 @@ var listCommand18 = defineCommand217({
|
|
|
68235
69725
|
});
|
|
68236
69726
|
|
|
68237
69727
|
// src/commands/studio/models.ts
|
|
68238
|
-
import { defineCommand as
|
|
69728
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
68239
69729
|
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.";
|
|
68240
69730
|
registerSchema({
|
|
68241
69731
|
command: "studio.models",
|
|
@@ -68322,7 +69812,7 @@ function buildModelCards(kind, model) {
|
|
|
68322
69812
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
68323
69813
|
return selected.map((id) => build(id));
|
|
68324
69814
|
}
|
|
68325
|
-
var modelsCommand =
|
|
69815
|
+
var modelsCommand = defineCommand223({
|
|
68326
69816
|
meta: {
|
|
68327
69817
|
name: "models",
|
|
68328
69818
|
description: `${DESCRIPTION3}
|
|
@@ -68369,13 +69859,13 @@ Examples:
|
|
|
68369
69859
|
});
|
|
68370
69860
|
|
|
68371
69861
|
// src/commands/studio/skills.ts
|
|
68372
|
-
import { defineCommand as
|
|
69862
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
68373
69863
|
registerSchema({
|
|
68374
69864
|
command: "studio.skills",
|
|
68375
69865
|
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.",
|
|
68376
69866
|
args: {}
|
|
68377
69867
|
});
|
|
68378
|
-
var skillsCommand =
|
|
69868
|
+
var skillsCommand = defineCommand224({
|
|
68379
69869
|
meta: {
|
|
68380
69870
|
name: "skills",
|
|
68381
69871
|
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"
|
|
@@ -68399,7 +69889,7 @@ var skillsCommand = defineCommand219({
|
|
|
68399
69889
|
});
|
|
68400
69890
|
|
|
68401
69891
|
// src/commands/studio/index.ts
|
|
68402
|
-
var studioCommand =
|
|
69892
|
+
var studioCommand = defineCommand225({
|
|
68403
69893
|
meta: {
|
|
68404
69894
|
name: "studio",
|
|
68405
69895
|
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.
|
|
@@ -68442,10 +69932,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
68442
69932
|
});
|
|
68443
69933
|
|
|
68444
69934
|
// src/commands/tag-manager/index.ts
|
|
68445
|
-
import { defineCommand as
|
|
69935
|
+
import { defineCommand as defineCommand229 } from "citty";
|
|
68446
69936
|
|
|
68447
69937
|
// src/commands/tag-manager/draft.ts
|
|
68448
|
-
import { defineCommand as
|
|
69938
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
68449
69939
|
|
|
68450
69940
|
// src/commands/tag-manager/shared.ts
|
|
68451
69941
|
import { readFileSync as readFileSync20 } from "fs";
|
|
@@ -68455,11 +69945,11 @@ function failValidation5(message) {
|
|
|
68455
69945
|
}
|
|
68456
69946
|
function requireTarget6(args5, entity) {
|
|
68457
69947
|
const positional = Array.isArray(args5._) ? args5._[0] : void 0;
|
|
68458
|
-
const
|
|
68459
|
-
if (typeof
|
|
69948
|
+
const target4 = args5.id ?? args5.target ?? positional;
|
|
69949
|
+
if (typeof target4 !== "string" || target4.length === 0) {
|
|
68460
69950
|
failValidation5(`pass the ${entity} id or path as the positional argument`);
|
|
68461
69951
|
}
|
|
68462
|
-
return
|
|
69952
|
+
return target4;
|
|
68463
69953
|
}
|
|
68464
69954
|
function loadJsonArg2(args5, flag3 = "json") {
|
|
68465
69955
|
const inline = args5[flag3];
|
|
@@ -68568,13 +70058,13 @@ registerSchema({
|
|
|
68568
70058
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
68569
70059
|
}
|
|
68570
70060
|
});
|
|
68571
|
-
var
|
|
70061
|
+
var draftCommand6 = defineCommand226({
|
|
68572
70062
|
meta: {
|
|
68573
70063
|
name: "draft",
|
|
68574
70064
|
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."
|
|
68575
70065
|
},
|
|
68576
70066
|
subCommands: {
|
|
68577
|
-
list:
|
|
70067
|
+
list: defineCommand226({
|
|
68578
70068
|
meta: {
|
|
68579
70069
|
name: "list",
|
|
68580
70070
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -68587,7 +70077,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68587
70077
|
await draftList2(args5.json === true, args5.chat);
|
|
68588
70078
|
}
|
|
68589
70079
|
}),
|
|
68590
|
-
show:
|
|
70080
|
+
show: defineCommand226({
|
|
68591
70081
|
meta: {
|
|
68592
70082
|
name: "show",
|
|
68593
70083
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -68604,7 +70094,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68604
70094
|
);
|
|
68605
70095
|
}
|
|
68606
70096
|
}),
|
|
68607
|
-
amend:
|
|
70097
|
+
amend: defineCommand226({
|
|
68608
70098
|
meta: {
|
|
68609
70099
|
name: "amend",
|
|
68610
70100
|
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."
|
|
@@ -68621,7 +70111,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68621
70111
|
});
|
|
68622
70112
|
}
|
|
68623
70113
|
}),
|
|
68624
|
-
remove:
|
|
70114
|
+
remove: defineCommand226({
|
|
68625
70115
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
68626
70116
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
68627
70117
|
run: async ({ args: args5 }) => {
|
|
@@ -68630,7 +70120,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68630
70120
|
});
|
|
68631
70121
|
}
|
|
68632
70122
|
}),
|
|
68633
|
-
clear:
|
|
70123
|
+
clear: defineCommand226({
|
|
68634
70124
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
68635
70125
|
run: async () => {
|
|
68636
70126
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -68640,7 +70130,7 @@ var draftCommand5 = defineCommand221({
|
|
|
68640
70130
|
});
|
|
68641
70131
|
|
|
68642
70132
|
// src/commands/tag-manager/read.ts
|
|
68643
|
-
import { defineCommand as
|
|
70133
|
+
import { defineCommand as defineCommand227 } from "citty";
|
|
68644
70134
|
registerSchema({
|
|
68645
70135
|
command: "tagManager.containers",
|
|
68646
70136
|
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.",
|
|
@@ -68681,7 +70171,7 @@ function containersHints(containers) {
|
|
|
68681
70171
|
}))
|
|
68682
70172
|
});
|
|
68683
70173
|
}
|
|
68684
|
-
var containersCommand =
|
|
70174
|
+
var containersCommand = defineCommand227({
|
|
68685
70175
|
meta: {
|
|
68686
70176
|
name: "containers",
|
|
68687
70177
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -68698,7 +70188,7 @@ Start here:
|
|
|
68698
70188
|
}
|
|
68699
70189
|
}
|
|
68700
70190
|
});
|
|
68701
|
-
var readCommand =
|
|
70191
|
+
var readCommand = defineCommand227({
|
|
68702
70192
|
meta: {
|
|
68703
70193
|
name: "read",
|
|
68704
70194
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -68740,7 +70230,7 @@ Examples:
|
|
|
68740
70230
|
});
|
|
68741
70231
|
|
|
68742
70232
|
// src/commands/tag-manager/write-commands.ts
|
|
68743
|
-
import { defineCommand as
|
|
70233
|
+
import { defineCommand as defineCommand228 } from "citty";
|
|
68744
70234
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
68745
70235
|
var ENTITIES = [
|
|
68746
70236
|
{
|
|
@@ -68796,10 +70286,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
68796
70286
|
});
|
|
68797
70287
|
}
|
|
68798
70288
|
function entityCommand(entity, noun, example) {
|
|
68799
|
-
return
|
|
70289
|
+
return defineCommand228({
|
|
68800
70290
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
68801
70291
|
subCommands: {
|
|
68802
|
-
create:
|
|
70292
|
+
create: defineCommand228({
|
|
68803
70293
|
meta: {
|
|
68804
70294
|
name: "create",
|
|
68805
70295
|
description: `Stage a new ${noun}
|
|
@@ -68821,7 +70311,7 @@ Examples:
|
|
|
68821
70311
|
});
|
|
68822
70312
|
}
|
|
68823
70313
|
}),
|
|
68824
|
-
update:
|
|
70314
|
+
update: defineCommand228({
|
|
68825
70315
|
meta: {
|
|
68826
70316
|
name: "update",
|
|
68827
70317
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -68841,7 +70331,7 @@ Examples:
|
|
|
68841
70331
|
});
|
|
68842
70332
|
}
|
|
68843
70333
|
}),
|
|
68844
|
-
delete:
|
|
70334
|
+
delete: defineCommand228({
|
|
68845
70335
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
68846
70336
|
args: {
|
|
68847
70337
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -68882,7 +70372,7 @@ function builtinTypes(args5) {
|
|
|
68882
70372
|
}
|
|
68883
70373
|
return raw.split(",").map((entry) => entry.trim());
|
|
68884
70374
|
}
|
|
68885
|
-
var builtinCommand =
|
|
70375
|
+
var builtinCommand = defineCommand228({
|
|
68886
70376
|
meta: {
|
|
68887
70377
|
name: "builtin",
|
|
68888
70378
|
description: `Enable or disable built-in variables
|
|
@@ -68892,7 +70382,7 @@ Examples:
|
|
|
68892
70382
|
baker tag-manager builtin disable --types formId`
|
|
68893
70383
|
},
|
|
68894
70384
|
subCommands: {
|
|
68895
|
-
enable:
|
|
70385
|
+
enable: defineCommand228({
|
|
68896
70386
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
68897
70387
|
args: {
|
|
68898
70388
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -68906,7 +70396,7 @@ Examples:
|
|
|
68906
70396
|
});
|
|
68907
70397
|
}
|
|
68908
70398
|
}),
|
|
68909
|
-
disable:
|
|
70399
|
+
disable: defineCommand228({
|
|
68910
70400
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
68911
70401
|
args: {
|
|
68912
70402
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -68924,7 +70414,7 @@ Examples:
|
|
|
68924
70414
|
});
|
|
68925
70415
|
|
|
68926
70416
|
// src/commands/tag-manager/index.ts
|
|
68927
|
-
var tagManagerCommand =
|
|
70417
|
+
var tagManagerCommand = defineCommand229({
|
|
68928
70418
|
meta: {
|
|
68929
70419
|
name: "tag-manager",
|
|
68930
70420
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -68956,12 +70446,12 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
68956
70446
|
variable: variableCommand,
|
|
68957
70447
|
folder: folderCommand,
|
|
68958
70448
|
builtin: builtinCommand,
|
|
68959
|
-
draft:
|
|
70449
|
+
draft: draftCommand6
|
|
68960
70450
|
}
|
|
68961
70451
|
});
|
|
68962
70452
|
|
|
68963
70453
|
// src/commands/tags/index.ts
|
|
68964
|
-
import { defineCommand as
|
|
70454
|
+
import { defineCommand as defineCommand230 } from "citty";
|
|
68965
70455
|
|
|
68966
70456
|
// src/commands/tags/shared.ts
|
|
68967
70457
|
function failApi3(err) {
|
|
@@ -69041,7 +70531,7 @@ async function listTags(json) {
|
|
|
69041
70531
|
var listArgs11 = {
|
|
69042
70532
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
69043
70533
|
};
|
|
69044
|
-
var listCommand19 =
|
|
70534
|
+
var listCommand19 = defineCommand230({
|
|
69045
70535
|
meta: {
|
|
69046
70536
|
name: "list",
|
|
69047
70537
|
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"
|
|
@@ -69060,7 +70550,7 @@ async function listDraft4(chat) {
|
|
|
69060
70550
|
failApi3(err);
|
|
69061
70551
|
}
|
|
69062
70552
|
}
|
|
69063
|
-
var
|
|
70553
|
+
var draftCommand7 = defineCommand230({
|
|
69064
70554
|
meta: {
|
|
69065
70555
|
name: "draft",
|
|
69066
70556
|
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."
|
|
@@ -69070,7 +70560,7 @@ var draftCommand6 = defineCommand225({
|
|
|
69070
70560
|
await listDraft4(args5.chat);
|
|
69071
70561
|
}
|
|
69072
70562
|
});
|
|
69073
|
-
var tagsCommand4 =
|
|
70563
|
+
var tagsCommand4 = defineCommand230({
|
|
69074
70564
|
meta: {
|
|
69075
70565
|
name: "tags",
|
|
69076
70566
|
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.
|
|
@@ -69088,7 +70578,7 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
69088
70578
|
},
|
|
69089
70579
|
subCommands: {
|
|
69090
70580
|
list: listCommand19,
|
|
69091
|
-
draft:
|
|
70581
|
+
draft: draftCommand7
|
|
69092
70582
|
},
|
|
69093
70583
|
// Bare `baker tags` lists the effective tags. `args` stays so citty knows this
|
|
69094
70584
|
// command's flags when it scans rawArgs for a subcommand name, and `default` (not
|
|
@@ -69099,10 +70589,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
69099
70589
|
});
|
|
69100
70590
|
|
|
69101
70591
|
// src/commands/testimonials/index.ts
|
|
69102
|
-
import { defineCommand as
|
|
70592
|
+
import { defineCommand as defineCommand234 } from "citty";
|
|
69103
70593
|
|
|
69104
70594
|
// src/commands/testimonials/get.ts
|
|
69105
|
-
import { defineCommand as
|
|
70595
|
+
import { defineCommand as defineCommand231 } from "citty";
|
|
69106
70596
|
registerSchema({
|
|
69107
70597
|
command: "testimonials.get",
|
|
69108
70598
|
description: "Get a single testimonial by ID",
|
|
@@ -69110,7 +70600,7 @@ registerSchema({
|
|
|
69110
70600
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
69111
70601
|
}
|
|
69112
70602
|
});
|
|
69113
|
-
var getCommand6 =
|
|
70603
|
+
var getCommand6 = defineCommand231({
|
|
69114
70604
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
69115
70605
|
args: {
|
|
69116
70606
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -69147,7 +70637,7 @@ var getCommand6 = defineCommand226({
|
|
|
69147
70637
|
});
|
|
69148
70638
|
|
|
69149
70639
|
// src/commands/testimonials/list.ts
|
|
69150
|
-
import { defineCommand as
|
|
70640
|
+
import { defineCommand as defineCommand232 } from "citty";
|
|
69151
70641
|
|
|
69152
70642
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
69153
70643
|
function resolveEmptyReason({
|
|
@@ -69304,7 +70794,7 @@ function buildListParams(args5) {
|
|
|
69304
70794
|
}
|
|
69305
70795
|
return params2;
|
|
69306
70796
|
}
|
|
69307
|
-
var listCommand20 =
|
|
70797
|
+
var listCommand20 = defineCommand232({
|
|
69308
70798
|
meta: {
|
|
69309
70799
|
name: "list",
|
|
69310
70800
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -69364,7 +70854,7 @@ var listCommand20 = defineCommand227({
|
|
|
69364
70854
|
});
|
|
69365
70855
|
|
|
69366
70856
|
// src/commands/testimonials/search.ts
|
|
69367
|
-
import { defineCommand as
|
|
70857
|
+
import { defineCommand as defineCommand233 } from "citty";
|
|
69368
70858
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
69369
70859
|
function languageBiasHint(results, requestedLanguage) {
|
|
69370
70860
|
if (requestedLanguage) {
|
|
@@ -69443,7 +70933,7 @@ function buildSearchRequest(query, args5) {
|
|
|
69443
70933
|
}
|
|
69444
70934
|
return body;
|
|
69445
70935
|
}
|
|
69446
|
-
var searchCommand3 =
|
|
70936
|
+
var searchCommand3 = defineCommand233({
|
|
69447
70937
|
meta: {
|
|
69448
70938
|
name: "search",
|
|
69449
70939
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -69507,7 +70997,7 @@ var searchCommand3 = defineCommand228({
|
|
|
69507
70997
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
69508
70998
|
|
|
69509
70999
|
// src/commands/testimonials/index.ts
|
|
69510
|
-
var testimonialsCommand =
|
|
71000
|
+
var testimonialsCommand = defineCommand234({
|
|
69511
71001
|
meta: {
|
|
69512
71002
|
name: "testimonials",
|
|
69513
71003
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -69529,10 +71019,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
69529
71019
|
});
|
|
69530
71020
|
|
|
69531
71021
|
// src/commands/videos/index.ts
|
|
69532
|
-
import { defineCommand as
|
|
71022
|
+
import { defineCommand as defineCommand242 } from "citty";
|
|
69533
71023
|
|
|
69534
71024
|
// src/commands/videos/delete.ts
|
|
69535
|
-
import { defineCommand as
|
|
71025
|
+
import { defineCommand as defineCommand235 } from "citty";
|
|
69536
71026
|
registerSchema({
|
|
69537
71027
|
command: "videos.delete",
|
|
69538
71028
|
description: "Delete a video by ID",
|
|
@@ -69546,7 +71036,7 @@ registerSchema({
|
|
|
69546
71036
|
}
|
|
69547
71037
|
}
|
|
69548
71038
|
});
|
|
69549
|
-
var deleteCommand4 =
|
|
71039
|
+
var deleteCommand4 = defineCommand235({
|
|
69550
71040
|
meta: {
|
|
69551
71041
|
name: "delete",
|
|
69552
71042
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -69587,7 +71077,7 @@ var deleteCommand4 = defineCommand230({
|
|
|
69587
71077
|
});
|
|
69588
71078
|
|
|
69589
71079
|
// src/commands/videos/describe.ts
|
|
69590
|
-
import { defineCommand as
|
|
71080
|
+
import { defineCommand as defineCommand236 } from "citty";
|
|
69591
71081
|
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.";
|
|
69592
71082
|
registerSchema({
|
|
69593
71083
|
command: "videos.describe",
|
|
@@ -69604,7 +71094,7 @@ registerSchema({
|
|
|
69604
71094
|
full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
|
|
69605
71095
|
}
|
|
69606
71096
|
});
|
|
69607
|
-
var describeCommand2 =
|
|
71097
|
+
var describeCommand2 = defineCommand236({
|
|
69608
71098
|
meta: {
|
|
69609
71099
|
name: "describe",
|
|
69610
71100
|
description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
|
|
@@ -69662,7 +71152,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
69662
71152
|
});
|
|
69663
71153
|
|
|
69664
71154
|
// src/commands/videos/get.ts
|
|
69665
|
-
import { defineCommand as
|
|
71155
|
+
import { defineCommand as defineCommand237 } from "citty";
|
|
69666
71156
|
registerSchema({
|
|
69667
71157
|
command: "videos.get",
|
|
69668
71158
|
description: "Get a single video by ID",
|
|
@@ -69670,7 +71160,7 @@ registerSchema({
|
|
|
69670
71160
|
id: { type: "string", description: "Video ID", required: true }
|
|
69671
71161
|
}
|
|
69672
71162
|
});
|
|
69673
|
-
var getCommand7 =
|
|
71163
|
+
var getCommand7 = defineCommand237({
|
|
69674
71164
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
69675
71165
|
args: {
|
|
69676
71166
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -69707,7 +71197,7 @@ var getCommand7 = defineCommand232({
|
|
|
69707
71197
|
});
|
|
69708
71198
|
|
|
69709
71199
|
// src/commands/videos/group.ts
|
|
69710
|
-
import { defineCommand as
|
|
71200
|
+
import { defineCommand as defineCommand238 } from "citty";
|
|
69711
71201
|
registerSchema({
|
|
69712
71202
|
command: "videos.group",
|
|
69713
71203
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -69716,7 +71206,7 @@ registerSchema({
|
|
|
69716
71206
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
69717
71207
|
}
|
|
69718
71208
|
});
|
|
69719
|
-
var groupCommand2 =
|
|
71209
|
+
var groupCommand2 = defineCommand238({
|
|
69720
71210
|
meta: {
|
|
69721
71211
|
name: "group",
|
|
69722
71212
|
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>"
|
|
@@ -69739,7 +71229,7 @@ var groupCommand2 = defineCommand233({
|
|
|
69739
71229
|
import { mkdtemp as mkdtemp3, rm as rm9, stat as stat12 } from "fs/promises";
|
|
69740
71230
|
import { tmpdir as tmpdir4 } from "os";
|
|
69741
71231
|
import path48 from "path";
|
|
69742
|
-
import { defineCommand as
|
|
71232
|
+
import { defineCommand as defineCommand239 } from "citty";
|
|
69743
71233
|
|
|
69744
71234
|
// src/lib/streamUpload.ts
|
|
69745
71235
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -69903,7 +71393,7 @@ registerSchema({
|
|
|
69903
71393
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
69904
71394
|
}
|
|
69905
71395
|
});
|
|
69906
|
-
var ingestCommand2 =
|
|
71396
|
+
var ingestCommand2 = defineCommand239({
|
|
69907
71397
|
meta: {
|
|
69908
71398
|
name: "ingest",
|
|
69909
71399
|
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"
|
|
@@ -70165,7 +71655,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
70165
71655
|
}
|
|
70166
71656
|
|
|
70167
71657
|
// src/commands/videos/search.ts
|
|
70168
|
-
import { defineCommand as
|
|
71658
|
+
import { defineCommand as defineCommand240 } from "citty";
|
|
70169
71659
|
registerSchema({
|
|
70170
71660
|
command: "videos.search",
|
|
70171
71661
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -70175,7 +71665,7 @@ registerSchema({
|
|
|
70175
71665
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
70176
71666
|
}
|
|
70177
71667
|
});
|
|
70178
|
-
var searchCommand4 =
|
|
71668
|
+
var searchCommand4 = defineCommand240({
|
|
70179
71669
|
meta: {
|
|
70180
71670
|
name: "search",
|
|
70181
71671
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -70227,7 +71717,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
70227
71717
|
// src/commands/videos/upload.ts
|
|
70228
71718
|
import { readFile as readFile34, stat as stat13 } from "fs/promises";
|
|
70229
71719
|
import { basename as basename3, extname as extname4 } from "path";
|
|
70230
|
-
import { defineCommand as
|
|
71720
|
+
import { defineCommand as defineCommand241 } from "citty";
|
|
70231
71721
|
var MIME_MAP = {
|
|
70232
71722
|
".mp4": "video/mp4",
|
|
70233
71723
|
".mov": "video/quicktime",
|
|
@@ -70269,7 +71759,7 @@ function detectContentType(filePath) {
|
|
|
70269
71759
|
function isRemoteUrl3(value) {
|
|
70270
71760
|
return /^https?:\/\//i.test(value);
|
|
70271
71761
|
}
|
|
70272
|
-
var uploadCommand2 =
|
|
71762
|
+
var uploadCommand2 = defineCommand241({
|
|
70273
71763
|
meta: {
|
|
70274
71764
|
name: "upload",
|
|
70275
71765
|
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"
|
|
@@ -70353,7 +71843,7 @@ var uploadCommand2 = defineCommand236({
|
|
|
70353
71843
|
});
|
|
70354
71844
|
|
|
70355
71845
|
// src/commands/videos/index.ts
|
|
70356
|
-
var videosCommand =
|
|
71846
|
+
var videosCommand = defineCommand242({
|
|
70357
71847
|
meta: {
|
|
70358
71848
|
name: "videos",
|
|
70359
71849
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
|
|
@@ -70382,10 +71872,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
70382
71872
|
});
|
|
70383
71873
|
|
|
70384
71874
|
// src/commands/winning-ads/index.ts
|
|
70385
|
-
import { defineCommand as
|
|
71875
|
+
import { defineCommand as defineCommand255 } from "citty";
|
|
70386
71876
|
|
|
70387
71877
|
// src/commands/winning-ads/advertisers.ts
|
|
70388
|
-
import { defineCommand as
|
|
71878
|
+
import { defineCommand as defineCommand243 } from "citty";
|
|
70389
71879
|
|
|
70390
71880
|
// src/commands/winning-ads/shared.ts
|
|
70391
71881
|
function splitList3(value) {
|
|
@@ -70438,7 +71928,7 @@ function advertiserNormalizer(record, full) {
|
|
|
70438
71928
|
last_synced_at: record.last_synced_at ?? null
|
|
70439
71929
|
};
|
|
70440
71930
|
}
|
|
70441
|
-
var advertisersCommand2 =
|
|
71931
|
+
var advertisersCommand2 = defineCommand243({
|
|
70442
71932
|
meta: {
|
|
70443
71933
|
name: "advertisers",
|
|
70444
71934
|
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'
|
|
@@ -70496,7 +71986,7 @@ var advertisersCommand2 = defineCommand238({
|
|
|
70496
71986
|
});
|
|
70497
71987
|
|
|
70498
71988
|
// src/commands/winning-ads/brief.ts
|
|
70499
|
-
import { defineCommand as
|
|
71989
|
+
import { defineCommand as defineCommand244 } from "citty";
|
|
70500
71990
|
registerSchema({
|
|
70501
71991
|
command: "winning-ads.brief",
|
|
70502
71992
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -70542,7 +72032,7 @@ function parseDna(raw) {
|
|
|
70542
72032
|
}
|
|
70543
72033
|
return parsed;
|
|
70544
72034
|
}
|
|
70545
|
-
var briefCommand =
|
|
72035
|
+
var briefCommand = defineCommand244({
|
|
70546
72036
|
meta: {
|
|
70547
72037
|
name: "brief",
|
|
70548
72038
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -70578,7 +72068,7 @@ var briefCommand = defineCommand239({
|
|
|
70578
72068
|
});
|
|
70579
72069
|
|
|
70580
72070
|
// src/commands/winning-ads/content.ts
|
|
70581
|
-
import { defineCommand as
|
|
72071
|
+
import { defineCommand as defineCommand245 } from "citty";
|
|
70582
72072
|
registerSchema({
|
|
70583
72073
|
command: "winning-ads.content",
|
|
70584
72074
|
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.",
|
|
@@ -70591,7 +72081,7 @@ registerSchema({
|
|
|
70591
72081
|
}
|
|
70592
72082
|
}
|
|
70593
72083
|
});
|
|
70594
|
-
var contentCommand =
|
|
72084
|
+
var contentCommand = defineCommand245({
|
|
70595
72085
|
meta: {
|
|
70596
72086
|
name: "content",
|
|
70597
72087
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -70640,7 +72130,7 @@ var contentCommand = defineCommand240({
|
|
|
70640
72130
|
});
|
|
70641
72131
|
|
|
70642
72132
|
// src/commands/winning-ads/feed.ts
|
|
70643
|
-
import { defineCommand as
|
|
72133
|
+
import { defineCommand as defineCommand246 } from "citty";
|
|
70644
72134
|
function buildFeedParams(input) {
|
|
70645
72135
|
const params2 = {};
|
|
70646
72136
|
const advertiser = splitList3(input.advertiser);
|
|
@@ -70692,7 +72182,7 @@ registerSchema({
|
|
|
70692
72182
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
70693
72183
|
}
|
|
70694
72184
|
});
|
|
70695
|
-
var feedCommand2 =
|
|
72185
|
+
var feedCommand2 = defineCommand246({
|
|
70696
72186
|
meta: {
|
|
70697
72187
|
name: "feed",
|
|
70698
72188
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -70777,7 +72267,7 @@ var feedCommand2 = defineCommand241({
|
|
|
70777
72267
|
});
|
|
70778
72268
|
|
|
70779
72269
|
// src/commands/winning-ads/follow.ts
|
|
70780
|
-
import { defineCommand as
|
|
72270
|
+
import { defineCommand as defineCommand247 } from "citty";
|
|
70781
72271
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
70782
72272
|
registerSchema({
|
|
70783
72273
|
command: "winning-ads.follow",
|
|
@@ -70792,7 +72282,7 @@ registerSchema({
|
|
|
70792
72282
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
70793
72283
|
}
|
|
70794
72284
|
});
|
|
70795
|
-
var followCommand =
|
|
72285
|
+
var followCommand = defineCommand247({
|
|
70796
72286
|
meta: {
|
|
70797
72287
|
name: "follow",
|
|
70798
72288
|
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'
|
|
@@ -70839,7 +72329,7 @@ var followCommand = defineCommand242({
|
|
|
70839
72329
|
});
|
|
70840
72330
|
|
|
70841
72331
|
// src/commands/winning-ads/follow-competitors.ts
|
|
70842
|
-
import { defineCommand as
|
|
72332
|
+
import { defineCommand as defineCommand248 } from "citty";
|
|
70843
72333
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
70844
72334
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
70845
72335
|
function buildFollowBatchBody(input) {
|
|
@@ -70872,7 +72362,7 @@ registerSchema({
|
|
|
70872
72362
|
}
|
|
70873
72363
|
}
|
|
70874
72364
|
});
|
|
70875
|
-
var followCompetitorsCommand =
|
|
72365
|
+
var followCompetitorsCommand = defineCommand248({
|
|
70876
72366
|
meta: {
|
|
70877
72367
|
name: "follow-competitors",
|
|
70878
72368
|
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"'
|
|
@@ -70947,7 +72437,7 @@ var followCompetitorsCommand = defineCommand243({
|
|
|
70947
72437
|
});
|
|
70948
72438
|
|
|
70949
72439
|
// src/commands/winning-ads/following.ts
|
|
70950
|
-
import { defineCommand as
|
|
72440
|
+
import { defineCommand as defineCommand249 } from "citty";
|
|
70951
72441
|
registerSchema({
|
|
70952
72442
|
command: "winning-ads.following",
|
|
70953
72443
|
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.",
|
|
@@ -71001,7 +72491,7 @@ function followingNormalizer(record, full) {
|
|
|
71001
72491
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
71002
72492
|
};
|
|
71003
72493
|
}
|
|
71004
|
-
var followingCommand =
|
|
72494
|
+
var followingCommand = defineCommand249({
|
|
71005
72495
|
meta: {
|
|
71006
72496
|
name: "following",
|
|
71007
72497
|
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"
|
|
@@ -71037,7 +72527,7 @@ var followingCommand = defineCommand244({
|
|
|
71037
72527
|
});
|
|
71038
72528
|
|
|
71039
72529
|
// src/commands/winning-ads/patterns.ts
|
|
71040
|
-
import { defineCommand as
|
|
72530
|
+
import { defineCommand as defineCommand250 } from "citty";
|
|
71041
72531
|
registerSchema({
|
|
71042
72532
|
command: "winning-ads.patterns",
|
|
71043
72533
|
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.",
|
|
@@ -71076,7 +72566,7 @@ function discriminatorRow(record) {
|
|
|
71076
72566
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
71077
72567
|
};
|
|
71078
72568
|
}
|
|
71079
|
-
var patternsCommand =
|
|
72569
|
+
var patternsCommand = defineCommand250({
|
|
71080
72570
|
meta: {
|
|
71081
72571
|
name: "patterns",
|
|
71082
72572
|
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"
|
|
@@ -71132,7 +72622,7 @@ var patternsCommand = defineCommand245({
|
|
|
71132
72622
|
});
|
|
71133
72623
|
|
|
71134
72624
|
// src/commands/winning-ads/search.ts
|
|
71135
|
-
import { defineCommand as
|
|
72625
|
+
import { defineCommand as defineCommand251 } from "citty";
|
|
71136
72626
|
registerSchema({
|
|
71137
72627
|
command: "winning-ads.search",
|
|
71138
72628
|
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.",
|
|
@@ -71205,15 +72695,15 @@ function setNumber(body, key, value) {
|
|
|
71205
72695
|
body[key] = Number(value);
|
|
71206
72696
|
}
|
|
71207
72697
|
}
|
|
71208
|
-
function setList(
|
|
71209
|
-
const
|
|
71210
|
-
if (
|
|
71211
|
-
|
|
72698
|
+
function setList(target4, key, value) {
|
|
72699
|
+
const list3 = splitList3(value);
|
|
72700
|
+
if (list3.length) {
|
|
72701
|
+
target4[key] = list3;
|
|
71212
72702
|
}
|
|
71213
72703
|
}
|
|
71214
|
-
function setString(
|
|
72704
|
+
function setString(target4, key, value) {
|
|
71215
72705
|
if (value) {
|
|
71216
|
-
|
|
72706
|
+
target4[key] = value;
|
|
71217
72707
|
}
|
|
71218
72708
|
}
|
|
71219
72709
|
function buildSearchBody2(args5) {
|
|
@@ -71270,7 +72760,7 @@ function reportSearchError(err) {
|
|
|
71270
72760
|
}
|
|
71271
72761
|
reportError2(err);
|
|
71272
72762
|
}
|
|
71273
|
-
var searchCommand5 =
|
|
72763
|
+
var searchCommand5 = defineCommand251({
|
|
71274
72764
|
meta: {
|
|
71275
72765
|
name: "search",
|
|
71276
72766
|
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"
|
|
@@ -71390,7 +72880,7 @@ var searchCommand5 = defineCommand246({
|
|
|
71390
72880
|
});
|
|
71391
72881
|
|
|
71392
72882
|
// src/commands/winning-ads/seeds.ts
|
|
71393
|
-
import { defineCommand as
|
|
72883
|
+
import { defineCommand as defineCommand252 } from "citty";
|
|
71394
72884
|
function leanRow(r) {
|
|
71395
72885
|
return {
|
|
71396
72886
|
key: r.key,
|
|
@@ -71418,7 +72908,7 @@ function makeSeedCommand(opts) {
|
|
|
71418
72908
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
71419
72909
|
}
|
|
71420
72910
|
});
|
|
71421
|
-
return
|
|
72911
|
+
return defineCommand252({
|
|
71422
72912
|
meta: { name: opts.name, description: opts.description },
|
|
71423
72913
|
args: {
|
|
71424
72914
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -71467,7 +72957,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
71467
72957
|
});
|
|
71468
72958
|
|
|
71469
72959
|
// src/commands/winning-ads/unfollow.ts
|
|
71470
|
-
import { defineCommand as
|
|
72960
|
+
import { defineCommand as defineCommand253 } from "citty";
|
|
71471
72961
|
registerSchema({
|
|
71472
72962
|
command: "winning-ads.unfollow",
|
|
71473
72963
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -71475,7 +72965,7 @@ registerSchema({
|
|
|
71475
72965
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
71476
72966
|
}
|
|
71477
72967
|
});
|
|
71478
|
-
var unfollowCommand =
|
|
72968
|
+
var unfollowCommand = defineCommand253({
|
|
71479
72969
|
meta: {
|
|
71480
72970
|
name: "unfollow",
|
|
71481
72971
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -71496,7 +72986,7 @@ var unfollowCommand = defineCommand248({
|
|
|
71496
72986
|
});
|
|
71497
72987
|
|
|
71498
72988
|
// src/commands/winning-ads/winners.ts
|
|
71499
|
-
import { defineCommand as
|
|
72989
|
+
import { defineCommand as defineCommand254 } from "citty";
|
|
71500
72990
|
registerSchema({
|
|
71501
72991
|
command: "winning-ads.winners",
|
|
71502
72992
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -71506,7 +72996,7 @@ registerSchema({
|
|
|
71506
72996
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
71507
72997
|
}
|
|
71508
72998
|
});
|
|
71509
|
-
var winnersCommand =
|
|
72999
|
+
var winnersCommand = defineCommand254({
|
|
71510
73000
|
meta: {
|
|
71511
73001
|
name: "winners",
|
|
71512
73002
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -71556,7 +73046,7 @@ var winnersCommand = defineCommand249({
|
|
|
71556
73046
|
});
|
|
71557
73047
|
|
|
71558
73048
|
// src/commands/winning-ads/index.ts
|
|
71559
|
-
var winningAdsCommand =
|
|
73049
|
+
var winningAdsCommand = defineCommand255({
|
|
71560
73050
|
meta: {
|
|
71561
73051
|
name: "winning-ads",
|
|
71562
73052
|
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.
|
|
@@ -71756,8 +73246,8 @@ function suggestFlag(unknown, command) {
|
|
|
71756
73246
|
const name = flag3.slice(2);
|
|
71757
73247
|
const def = args5[name] ?? args5[camel(name)];
|
|
71758
73248
|
const described = def && typeof def === "object" ? def.description : void 0;
|
|
71759
|
-
const
|
|
71760
|
-
return
|
|
73249
|
+
const description2 = typeof described === "string" ? described.split(/(?<!\b(?:e\.g|i\.e|vs))\.\s/)[0]?.trim().replace(/\.$/, "") : "";
|
|
73250
|
+
return description2 ? { flag: flag3, description: description2 } : { flag: flag3 };
|
|
71761
73251
|
}
|
|
71762
73252
|
function suggestionText(suggestion) {
|
|
71763
73253
|
if (!suggestion) {
|
|
@@ -71767,12 +73257,12 @@ function suggestionText(suggestion) {
|
|
|
71767
73257
|
}
|
|
71768
73258
|
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. ";
|
|
71769
73259
|
function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
71770
|
-
const
|
|
73260
|
+
const list3 = unknown.join(", ");
|
|
71771
73261
|
return {
|
|
71772
73262
|
ok: false,
|
|
71773
73263
|
error: {
|
|
71774
73264
|
code: "UNKNOWN_ARGUMENT",
|
|
71775
|
-
message: `${
|
|
73265
|
+
message: `${list3} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
71776
73266
|
fix: {
|
|
71777
73267
|
action: hasSchema ? "check_schema" : "check_help",
|
|
71778
73268
|
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.`
|
|
@@ -71883,7 +73373,7 @@ function getCliVersion() {
|
|
|
71883
73373
|
}
|
|
71884
73374
|
|
|
71885
73375
|
// src/cli.ts
|
|
71886
|
-
var main =
|
|
73376
|
+
var main = defineCommand256({
|
|
71887
73377
|
meta: {
|
|
71888
73378
|
name: "baker",
|
|
71889
73379
|
version: getCliVersion(),
|