@koda-sl/baker-cli 0.372.0-dev.0d1659d6a → 0.373.0-dev.56c2ad392
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 +22 -2
- package/dist/cli.js +1612 -470
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -133,7 +133,7 @@ import {
|
|
|
133
133
|
} from "./chunk-7YNOGIWQ.js";
|
|
134
134
|
|
|
135
135
|
// src/cli.ts
|
|
136
|
-
import { defineCommand as
|
|
136
|
+
import { defineCommand as defineCommand250, runMain } from "citty";
|
|
137
137
|
|
|
138
138
|
// src/cache-flag.ts
|
|
139
139
|
var NO_CACHE_ARG = {
|
|
@@ -161,8 +161,8 @@ function cacheFlagForParser(argv) {
|
|
|
161
161
|
}
|
|
162
162
|
function rewriteBeforeDoubleDash(argv, rewrite) {
|
|
163
163
|
const end = argv.indexOf("--");
|
|
164
|
-
const
|
|
165
|
-
return argv.flatMap((token, index) => index >=
|
|
164
|
+
const limit2 = end === -1 ? argv.length : end;
|
|
165
|
+
return argv.flatMap((token, index) => index >= limit2 ? [token] : rewrite(token));
|
|
166
166
|
}
|
|
167
167
|
|
|
168
168
|
// src/commands/actions/index.ts
|
|
@@ -1492,7 +1492,7 @@ var audienceCreateSchema = z3.object({
|
|
|
1492
1492
|
}
|
|
1493
1493
|
});
|
|
1494
1494
|
var ENGAGEMENT_LOOKBACK_DAYS = [7, 14, 28, 30, 60, 90, 180, 365];
|
|
1495
|
-
var WEBSITE_LOOKBACK_DAYS = ENGAGEMENT_LOOKBACK_DAYS.filter((
|
|
1495
|
+
var WEBSITE_LOOKBACK_DAYS = ENGAGEMENT_LOOKBACK_DAYS.filter((days2) => days2 >= 14 && days2 <= 180);
|
|
1496
1496
|
var EVENT_LOOKBACK_DAYS = [730];
|
|
1497
1497
|
var WEBSITE_SOURCE_PLATFORM = "LINKEDIN_WEBSITE_RETARGETING";
|
|
1498
1498
|
var TRIGGER_SOURCE_TYPE_BY_PLATFORM = { [WEBSITE_SOURCE_PLATFORM]: "WEBSITE" };
|
|
@@ -1578,9 +1578,9 @@ function retargetingConfigProblems(raw) {
|
|
|
1578
1578
|
const expectedTriggerSource = TRIGGER_SOURCE_TYPE_BY_PLATFORM[sourcePlatform] ?? sourcePlatform;
|
|
1579
1579
|
for (const rule of rules.data) {
|
|
1580
1580
|
problems.push(...ruleProblems(rule, sourcePlatform ? expectedTriggerSource : void 0));
|
|
1581
|
-
const
|
|
1582
|
-
if (!allowed.includes(
|
|
1583
|
-
problems.push(`lookback ${
|
|
1581
|
+
const days2 = rule.timeFrame.timeSpan.duration;
|
|
1582
|
+
if (!allowed.includes(days2)) {
|
|
1583
|
+
problems.push(`lookback ${days2} days is not offered for ${sourcePlatform} \u2014 use ${allowed.join(", ")}`);
|
|
1584
1584
|
}
|
|
1585
1585
|
}
|
|
1586
1586
|
const shapes = new Set(rules.data.map((rule) => `${rule.engagementTrigger}|${rule.timeFrame.timeSpan.duration}`));
|
|
@@ -5897,7 +5897,11 @@ var REJECTION_CODES = [
|
|
|
5897
5897
|
"missing_identity",
|
|
5898
5898
|
"invalid_timestamp",
|
|
5899
5899
|
"invalid_value",
|
|
5900
|
-
"batch_too_large"
|
|
5900
|
+
"batch_too_large",
|
|
5901
|
+
// Appended, never inserted: the set a client branches on grows, and no code
|
|
5902
|
+
// it already handles changes meaning.
|
|
5903
|
+
"invalid_items",
|
|
5904
|
+
"invalid_consent"
|
|
5901
5905
|
];
|
|
5902
5906
|
var EVENT_INGEST_BATCH_MAX = 500;
|
|
5903
5907
|
var EVENT_INGEST_BODY_MAX_BYTES = 8 * 1024 * 1024;
|
|
@@ -5910,12 +5914,15 @@ function validateEventName(name) {
|
|
|
5910
5914
|
if (value === "" || value.length > MAX_EVENT_NAME || !EVENT_NAME.test(value)) return "invalid_name";
|
|
5911
5915
|
return null;
|
|
5912
5916
|
}
|
|
5917
|
+
var MAX_ITEM_QUANTITY = 1e6;
|
|
5913
5918
|
var REJECTION_MESSAGES = {
|
|
5914
5919
|
invalid_event_id: "event_id, when sent, must be 1-128 characters of A-Z a-z 0-9 . _ : -",
|
|
5915
5920
|
invalid_name: "event_name is required: up to 80 characters of letters (any language), digits, spaces, . _ and -, starting with a letter or a digit",
|
|
5916
5921
|
missing_identity: "user_data named nobody, and no url named a page",
|
|
5917
5922
|
invalid_timestamp: "event_time must be an ISO-8601 instant with an offset or Unix seconds, and not in the future",
|
|
5918
5923
|
invalid_value: "value and currency go together: a non-negative decimal and an ISO-4217 code",
|
|
5924
|
+
invalid_items: "each item names a product_id, variant_id or feed_id; quantity is a whole number from 1 to 1000000; price is a non-negative decimal sent with a currency",
|
|
5925
|
+
invalid_consent: "consent.analytics and consent.marketing, when sent, are granted or denied",
|
|
5919
5926
|
batch_too_large: `a request carries at most ${EVENT_INGEST_BATCH_MAX} events and ${EVENT_INGEST_BODY_MAX_BYTES / (1024 * 1024)} MB`
|
|
5920
5927
|
};
|
|
5921
5928
|
|
|
@@ -7136,12 +7143,12 @@ function parseClause(clause) {
|
|
|
7136
7143
|
return { error: `"${clause}" has no operator this understands. ${EXPRESSION_HELP}` };
|
|
7137
7144
|
}
|
|
7138
7145
|
function parseConditionsExpression(expression) {
|
|
7139
|
-
const
|
|
7140
|
-
if ("error" in
|
|
7141
|
-
return { ok: false, error:
|
|
7146
|
+
const split2 = splitClauses(expression);
|
|
7147
|
+
if ("error" in split2) {
|
|
7148
|
+
return { ok: false, error: split2.error };
|
|
7142
7149
|
}
|
|
7143
7150
|
const rules = [];
|
|
7144
|
-
for (const clause of
|
|
7151
|
+
for (const clause of split2.clauses) {
|
|
7145
7152
|
if (clause.length === 0) {
|
|
7146
7153
|
return { ok: false, error: `An empty rule. ${EXPRESSION_HELP}` };
|
|
7147
7154
|
}
|
|
@@ -7154,7 +7161,7 @@ function parseConditionsExpression(expression) {
|
|
|
7154
7161
|
if (rules.length > MAX_CONDITION_RULES) {
|
|
7155
7162
|
return { ok: false, error: `At most ${MAX_CONDITION_RULES} rules.` };
|
|
7156
7163
|
}
|
|
7157
|
-
return { ok: true, conditions: { match:
|
|
7164
|
+
return { ok: true, conditions: { match: split2.match, rules } };
|
|
7158
7165
|
}
|
|
7159
7166
|
|
|
7160
7167
|
// ../api/src/scheduledAgents.ts
|
|
@@ -7294,7 +7301,8 @@ var TRIGGER_KINDS = {
|
|
|
7294
7301
|
"utm_source",
|
|
7295
7302
|
"utm_medium",
|
|
7296
7303
|
"utm_campaign",
|
|
7297
|
-
"properties.<name>"
|
|
7304
|
+
"properties.<name>",
|
|
7305
|
+
"items"
|
|
7298
7306
|
],
|
|
7299
7307
|
keywords: ["purchase", "signup", "conversion", "analytics", "tracking", "hubspot", "crm", "deal", "funnel", "lead"]
|
|
7300
7308
|
},
|
|
@@ -8610,12 +8618,12 @@ function advisoryHint(name, description) {
|
|
|
8610
8618
|
return executable ? { kind: "executable", ...executable } : null;
|
|
8611
8619
|
}
|
|
8612
8620
|
var ACTIONS_LIST_DEFAULT_LIMIT = 500;
|
|
8613
|
-
function buildListHints({ returned, limit }) {
|
|
8614
|
-
if (returned <
|
|
8621
|
+
function buildListHints({ returned, limit: limit2 }) {
|
|
8622
|
+
if (returned < limit2) {
|
|
8615
8623
|
return [];
|
|
8616
8624
|
}
|
|
8617
8625
|
return [
|
|
8618
|
-
`This list is capped at ${
|
|
8626
|
+
`This list is capped at ${limit2} Tasks and came back full, so older Tasks exist that are NOT shown. Do not treat it as the whole backlog \u2014 re-run with --limit ${limit2 * 2} (or narrow with --status / --search).`
|
|
8619
8627
|
];
|
|
8620
8628
|
}
|
|
8621
8629
|
|
|
@@ -9394,9 +9402,9 @@ function resolveWindow(args5) {
|
|
|
9394
9402
|
const todayStart = startOfLocalDay(new Date(now));
|
|
9395
9403
|
return { fromMs: todayStart - DAY_MS, toMs: todayStart };
|
|
9396
9404
|
}
|
|
9397
|
-
const
|
|
9398
|
-
if (
|
|
9399
|
-
return { fromMs: now - Number(
|
|
9405
|
+
const days2 = /^(\d+)d$/.exec(since);
|
|
9406
|
+
if (days2) {
|
|
9407
|
+
return { fromMs: now - Number(days2[1]) * DAY_MS, toMs: now };
|
|
9400
9408
|
}
|
|
9401
9409
|
return failValidation(`--since must be one of: today | yesterday | <N>d (e.g. 7d). Got: ${since}`);
|
|
9402
9410
|
}
|
|
@@ -9794,15 +9802,15 @@ import { defineCommand as defineCommand19 } from "citty";
|
|
|
9794
9802
|
function listed(resources) {
|
|
9795
9803
|
return resources.map((resource) => resource.label ? `${resource.id} (${resource.label})` : resource.id).join("; ");
|
|
9796
9804
|
}
|
|
9797
|
-
function connectedResourceHints({ plural, singular, flag:
|
|
9805
|
+
function connectedResourceHints({ plural, singular, flag: flag3, resources }) {
|
|
9798
9806
|
if (resources.length === 0) {
|
|
9799
9807
|
return [];
|
|
9800
9808
|
}
|
|
9801
9809
|
if (resources.length === 1) {
|
|
9802
|
-
return [`This company connected one ${singular}: ${listed(resources)}. Commands use it unless you pass ${
|
|
9810
|
+
return [`This company connected one ${singular}: ${listed(resources)}. Commands use it unless you pass ${flag3}.`];
|
|
9803
9811
|
}
|
|
9804
9812
|
return [
|
|
9805
|
-
`This company connected ${resources.length} ${plural}: ${listed(resources)}. Each command works on one, so pass ${
|
|
9813
|
+
`This company connected ${resources.length} ${plural}: ${listed(resources)}. Each command works on one, so pass ${flag3} \u2014 nothing is picked for you. A question about the whole business covers all ${resources.length}: answering from one and reporting it as the total is wrong.`
|
|
9806
9814
|
];
|
|
9807
9815
|
}
|
|
9808
9816
|
|
|
@@ -10025,8 +10033,8 @@ var CHANGE_SCOPE_MAX_DAYS = {
|
|
|
10025
10033
|
};
|
|
10026
10034
|
var DEFAULT_CHANGE_DAYS = 7;
|
|
10027
10035
|
var MAX_CHANGE_DAYS = CHANGE_SCOPE_MAX_DAYS.summary;
|
|
10028
|
-
function isChangeLookbackWithinReach(
|
|
10029
|
-
return
|
|
10036
|
+
function isChangeLookbackWithinReach(days2, scope) {
|
|
10037
|
+
return days2 <= CHANGE_SCOPE_MAX_DAYS[scope];
|
|
10030
10038
|
}
|
|
10031
10039
|
|
|
10032
10040
|
// ../api/src/ads-google/geo-constants.ts
|
|
@@ -10459,8 +10467,8 @@ function equivalentBetween(literal, now) {
|
|
|
10459
10467
|
const unit = rolling[2];
|
|
10460
10468
|
if (n < 1) return null;
|
|
10461
10469
|
if (unit === "DAYS" || unit === "WEEKS") {
|
|
10462
|
-
const
|
|
10463
|
-
return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() -
|
|
10470
|
+
const days2 = unit === "DAYS" ? n : n * 7;
|
|
10471
|
+
return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() - days2), yesterday);
|
|
10464
10472
|
}
|
|
10465
10473
|
const months = unit === "MONTHS" ? n : n * 12;
|
|
10466
10474
|
return range(monthsBefore(today, months), yesterday);
|
|
@@ -10506,13 +10514,13 @@ function resolveChangesWindow(input) {
|
|
|
10506
10514
|
}
|
|
10507
10515
|
};
|
|
10508
10516
|
}
|
|
10509
|
-
const
|
|
10510
|
-
if (!Number.isInteger(
|
|
10517
|
+
const days2 = input.days ?? DEFAULT_CHANGE_DAYS;
|
|
10518
|
+
if (!Number.isInteger(days2) || days2 < 1) {
|
|
10511
10519
|
return {
|
|
10512
10520
|
ok: false,
|
|
10513
10521
|
error: {
|
|
10514
10522
|
code: "INVALID_LOOKBACK",
|
|
10515
|
-
message: `--days must be a whole number of days, got '${
|
|
10523
|
+
message: `--days must be a whole number of days, got '${days2}'.`,
|
|
10516
10524
|
fix: {
|
|
10517
10525
|
action: "retry_with_flag",
|
|
10518
10526
|
explanation: `Pass --days as a positive integer, e.g. --days ${DEFAULT_CHANGE_DAYS}.`
|
|
@@ -10520,32 +10528,32 @@ function resolveChangesWindow(input) {
|
|
|
10520
10528
|
}
|
|
10521
10529
|
};
|
|
10522
10530
|
}
|
|
10523
|
-
if (!isChangeLookbackWithinReach(
|
|
10524
|
-
return { ok: false, error: lookbackTooLong(scope,
|
|
10531
|
+
if (!isChangeLookbackWithinReach(days2, scope)) {
|
|
10532
|
+
return { ok: false, error: lookbackTooLong(scope, days2, CHANGE_SCOPE_MAX_DAYS[scope]) };
|
|
10525
10533
|
}
|
|
10526
|
-
return { ok: true, scope, days, hints: hintsFor(scope,
|
|
10534
|
+
return { ok: true, scope, days: days2, hints: hintsFor(scope, days2) };
|
|
10527
10535
|
}
|
|
10528
|
-
function lookbackTooLong(scope,
|
|
10529
|
-
if (scope === "detail" &&
|
|
10536
|
+
function lookbackTooLong(scope, days2, max) {
|
|
10537
|
+
if (scope === "detail" && days2 <= CHANGE_SCOPE_MAX_DAYS.summary) {
|
|
10530
10538
|
return {
|
|
10531
10539
|
code: "LOOKBACK_TOO_LONG",
|
|
10532
|
-
message: `Google keeps field-level change detail for ${max} days only; ${
|
|
10540
|
+
message: `Google keeps field-level change detail for ${max} days only; ${days2} days is outside that window.`,
|
|
10533
10541
|
fix: {
|
|
10534
10542
|
action: "narrow_date_range",
|
|
10535
|
-
explanation: `Re-run with --scope summary --days ${
|
|
10543
|
+
explanation: `Re-run with --scope summary --days ${days2} to reach back ${CHANGE_SCOPE_MAX_DAYS.summary} days. Summary tells you which campaigns, ad groups, ads and criteria changed and when, but not the old and new values \u2014 read the resource itself for current values.`
|
|
10536
10544
|
}
|
|
10537
10545
|
};
|
|
10538
10546
|
}
|
|
10539
10547
|
return {
|
|
10540
10548
|
code: "LOOKBACK_TOO_LONG",
|
|
10541
|
-
message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${
|
|
10549
|
+
message: `Google's account history API reaches back ${CHANGE_SCOPE_MAX_DAYS.summary} days at most; ${days2} days is outside that window.`,
|
|
10542
10550
|
fix: {
|
|
10543
10551
|
action: "use_different_resource",
|
|
10544
10552
|
explanation: `Do not abort \u2014 infer the change from performance instead. Query monthly metrics per campaign (${monthlySpendTrendQuery()}) to see which campaigns stopped or started spending. That shows what changed and when, though not who changed it. Older history exists only in the Google Ads web UI, which has no API \u2014 ask the user to check it if the 'who' matters.`
|
|
10545
10553
|
}
|
|
10546
10554
|
};
|
|
10547
10555
|
}
|
|
10548
|
-
function hintsFor(scope,
|
|
10556
|
+
function hintsFor(scope, days2) {
|
|
10549
10557
|
const hints2 = [];
|
|
10550
10558
|
if (scope === "detail") {
|
|
10551
10559
|
hints2.push(
|
|
@@ -10555,7 +10563,7 @@ function hintsFor(scope, days) {
|
|
|
10555
10563
|
hints2.push(
|
|
10556
10564
|
"Summary history reports which resources changed and when, not old and new values. To see what a changed resource looks like now, query it by resource_name."
|
|
10557
10565
|
);
|
|
10558
|
-
if (
|
|
10566
|
+
if (days2 > CHANGE_SCOPE_MAX_DAYS.detail) {
|
|
10559
10567
|
hints2.push(
|
|
10560
10568
|
`Changes inside the last ${CHANGE_SCOPE_MAX_DAYS.detail} days also have field-level detail \u2014 re-run with --scope detail for those.`
|
|
10561
10569
|
);
|
|
@@ -11001,11 +11009,11 @@ var CORRECTION_RULES = [
|
|
|
11001
11009
|
{
|
|
11002
11010
|
matchApiError: /changeEventError\W{0,4}START_DATE_TOO_OLD/i,
|
|
11003
11011
|
fix: (ctx) => {
|
|
11004
|
-
const
|
|
11012
|
+
const limit2 = ctx.originalQuery.match(/LIMIT\s+(\d+)/i)?.[1] ?? "50";
|
|
11005
11013
|
const requested = ctx.originalQuery.match(/change_date_time\s*>=\s*'([^']+)'/i)?.[1]?.slice(0, 10);
|
|
11006
11014
|
const oldestStart = new Date(Date.now() - 89 * 24 * 60 * 60 * 1e3).toISOString().slice(0, 10);
|
|
11007
11015
|
const start = requested && requested > oldestStart ? requested : oldestStart;
|
|
11008
|
-
const corrected = `SELECT change_status.last_change_date_time, change_status.resource_type, change_status.resource_status, change_status.resource_name, change_status.campaign, change_status.ad_group FROM change_status WHERE change_status.last_change_date_time >= '${start}' ORDER BY change_status.last_change_date_time DESC LIMIT ${
|
|
11016
|
+
const corrected = `SELECT change_status.last_change_date_time, change_status.resource_type, change_status.resource_status, change_status.resource_name, change_status.campaign, change_status.ad_group FROM change_status WHERE change_status.last_change_date_time >= '${start}' ORDER BY change_status.last_change_date_time DESC LIMIT ${limit2}`;
|
|
11009
11017
|
return {
|
|
11010
11018
|
action: "use_different_resource",
|
|
11011
11019
|
correctedCommand: buildCommand(corrected, ctx),
|
|
@@ -11397,8 +11405,8 @@ import { defineCommand as defineCommand22 } from "citty";
|
|
|
11397
11405
|
import { readFileSync as readFileSync2 } from "fs";
|
|
11398
11406
|
|
|
11399
11407
|
// src/lib/repeatedFlags.ts
|
|
11400
|
-
function repeatedFlagValues(rawArgs,
|
|
11401
|
-
const long = `--${
|
|
11408
|
+
function repeatedFlagValues(rawArgs, flag3) {
|
|
11409
|
+
const long = `--${flag3}`;
|
|
11402
11410
|
const inline = `${long}=`;
|
|
11403
11411
|
const values = [];
|
|
11404
11412
|
for (let i = 0; i < rawArgs.length; i++) {
|
|
@@ -11416,9 +11424,9 @@ function repeatedFlagValues(rawArgs, flag2) {
|
|
|
11416
11424
|
}
|
|
11417
11425
|
return values;
|
|
11418
11426
|
}
|
|
11419
|
-
function repeatedValues(rawArgs,
|
|
11427
|
+
function repeatedValues(rawArgs, flag3, parsed) {
|
|
11420
11428
|
if (rawArgs !== void 0) {
|
|
11421
|
-
const fromLine = repeatedFlagValues(rawArgs,
|
|
11429
|
+
const fromLine = repeatedFlagValues(rawArgs, flag3);
|
|
11422
11430
|
if (fromLine.length > 0) return fromLine;
|
|
11423
11431
|
}
|
|
11424
11432
|
if (Array.isArray(parsed)) return parsed.filter((v) => typeof v === "string");
|
|
@@ -11444,8 +11452,8 @@ function booleanWordPositionalError(args5, entity) {
|
|
|
11444
11452
|
}
|
|
11445
11453
|
const value = word.toLowerCase();
|
|
11446
11454
|
const raised = Object.keys(args5).filter((key) => key !== "_" && args5[key] === true);
|
|
11447
|
-
const named = raised.length > 0 ? raised.map((
|
|
11448
|
-
const fix = raised.length > 0 ? raised.map((
|
|
11455
|
+
const named = raised.length > 0 ? raised.map((flag3) => `--${flag3}`).join(" or ") : "a boolean flag";
|
|
11456
|
+
const fix = raised.length > 0 ? raised.map((flag3) => `--${flag3}=${value}`).join(" or ") : `--<flag>=${value}`;
|
|
11449
11457
|
const negated = raised.length === 1 && value === "false" ? ` (or --no-${raised[0]})` : "";
|
|
11450
11458
|
return `"${word}" was read as the ${entity} target, not as a value for ${named}. A boolean flag written with a space is set to TRUE and the word is dropped \u2014 attach it instead: ${fix}${negated}.`;
|
|
11451
11459
|
}
|
|
@@ -12053,19 +12061,19 @@ function requireTarget(args5, entity) {
|
|
|
12053
12061
|
}
|
|
12054
12062
|
return target2;
|
|
12055
12063
|
}
|
|
12056
|
-
function requireStringFlag(value,
|
|
12064
|
+
function requireStringFlag(value, flag3) {
|
|
12057
12065
|
if (typeof value !== "string" || value.length === 0) {
|
|
12058
|
-
failWriteValidation(`${
|
|
12066
|
+
failWriteValidation(`${flag3} is required`);
|
|
12059
12067
|
}
|
|
12060
12068
|
return value;
|
|
12061
12069
|
}
|
|
12062
|
-
function microsFlag(value,
|
|
12070
|
+
function microsFlag(value, flag3) {
|
|
12063
12071
|
if (value === void 0 || value === null || value === "") {
|
|
12064
12072
|
return void 0;
|
|
12065
12073
|
}
|
|
12066
12074
|
const num4 = Number(value);
|
|
12067
12075
|
if (Number.isNaN(num4) || num4 <= 0) {
|
|
12068
|
-
failWriteValidation(`${
|
|
12076
|
+
failWriteValidation(`${flag3} must be a positive amount (major currency units, e.g. 50 or 50.00)`);
|
|
12069
12077
|
}
|
|
12070
12078
|
return toMicros(num4);
|
|
12071
12079
|
}
|
|
@@ -12992,13 +13000,13 @@ function buildStatusScope(statusFields, includePaused) {
|
|
|
12992
13000
|
}
|
|
12993
13001
|
function expandPreset(preset, params2, now = /* @__PURE__ */ new Date()) {
|
|
12994
13002
|
const dateRange = params2.dateRange ?? preset.defaultDateRange;
|
|
12995
|
-
const
|
|
13003
|
+
const limit2 = params2.limit ?? preset.defaultLimit;
|
|
12996
13004
|
if (preset.gaqlTemplate.includes("{dateRange}") && !isValidDateRange(dateRange)) {
|
|
12997
13005
|
return { query: "", dateRangeError: dateRangeError(dateRange, now) };
|
|
12998
13006
|
}
|
|
12999
13007
|
const statusScope = buildStatusScope(preset.statusFields, params2.includePaused ?? false);
|
|
13000
13008
|
const range = dateRange.trim();
|
|
13001
|
-
const query = preset.gaqlTemplate.replace(/DURING\s+\{dateRange\}/g, BETWEEN_RE.test(range) ? range : `DURING ${range}`).replace(/\{dateRange\}/g, range).replace(/\{limit\}/g, String(
|
|
13009
|
+
const query = preset.gaqlTemplate.replace(/DURING\s+\{dateRange\}/g, BETWEEN_RE.test(range) ? range : `DURING ${range}`).replace(/\{dateRange\}/g, range).replace(/\{limit\}/g, String(limit2)).replace(/\{statusScope\}/g, statusScope);
|
|
13002
13010
|
return { query };
|
|
13003
13011
|
}
|
|
13004
13012
|
|
|
@@ -13118,7 +13126,7 @@ function addRequiredAncestorFields(query) {
|
|
|
13118
13126
|
]
|
|
13119
13127
|
};
|
|
13120
13128
|
}
|
|
13121
|
-
function applyAutoFixes(query,
|
|
13129
|
+
function applyAutoFixes(query, limit2) {
|
|
13122
13130
|
let corrected = query;
|
|
13123
13131
|
const warnings = [];
|
|
13124
13132
|
if (/(?<![\w.])keyword\.text\b/.test(corrected)) {
|
|
@@ -13149,7 +13157,7 @@ function applyAutoFixes(query, limit) {
|
|
|
13149
13157
|
warnings.push({ code: "ENUM_CORRECTED", message: "ad_group.status ACTIVE \u2192 ENABLED" });
|
|
13150
13158
|
}
|
|
13151
13159
|
if (!/\bLIMIT\b/i.test(corrected)) {
|
|
13152
|
-
const effectiveLimit =
|
|
13160
|
+
const effectiveLimit = limit2 ?? 200;
|
|
13153
13161
|
corrected = `${corrected.trimEnd()} LIMIT ${effectiveLimit}`;
|
|
13154
13162
|
if (!isSingleRowRead(corrected)) {
|
|
13155
13163
|
warnings.push({ code: "AUTO_LIMIT", message: `Added LIMIT ${effectiveLimit}. Use --limit to override.` });
|
|
@@ -13267,7 +13275,7 @@ function rejectContainsCall(query, customerId) {
|
|
|
13267
13275
|
}
|
|
13268
13276
|
};
|
|
13269
13277
|
}
|
|
13270
|
-
function validatePreflight(query, customerId,
|
|
13278
|
+
function validatePreflight(query, customerId, limit2) {
|
|
13271
13279
|
const warnings = [];
|
|
13272
13280
|
const corrected = query;
|
|
13273
13281
|
const firstWord = corrected.trim().split(/\s+/)[0]?.toUpperCase();
|
|
@@ -13343,7 +13351,7 @@ function validatePreflight(query, customerId, limit) {
|
|
|
13343
13351
|
message: "ad_group_criterion returns BOTH positive and negative keywords. Add ad_group_criterion.negative to SELECT or filter with WHERE ad_group_criterion.negative = FALSE (positives) / TRUE (negatives). Use --preset positive-keywords or negative-keywords instead."
|
|
13344
13352
|
});
|
|
13345
13353
|
}
|
|
13346
|
-
const { query: autoFixed, warnings: autoFixWarnings } = applyAutoFixes(corrected,
|
|
13354
|
+
const { query: autoFixed, warnings: autoFixWarnings } = applyAutoFixes(corrected, limit2);
|
|
13347
13355
|
warnings.push(...autoFixWarnings);
|
|
13348
13356
|
const analysis = analyzeServingChain(autoFixed);
|
|
13349
13357
|
if (!analysis) return { valid: true, correctedQuery: autoFixed, warnings };
|
|
@@ -13612,12 +13620,12 @@ function writeRowsToFile(filePath, rows, fields, append) {
|
|
|
13612
13620
|
writeFileSync(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
13613
13621
|
}
|
|
13614
13622
|
}
|
|
13615
|
-
function effectiveRowLimit(finalQuery,
|
|
13623
|
+
function effectiveRowLimit(finalQuery, limit2, all = false) {
|
|
13616
13624
|
if (isSingleRowRead(finalQuery)) return void 0;
|
|
13617
13625
|
const match = finalQuery.match(/\bLIMIT\s+(\d+)/i);
|
|
13618
13626
|
const statementLimit = match?.[1] ? Number(match[1]) : void 0;
|
|
13619
13627
|
if (all) return statementLimit;
|
|
13620
|
-
return statementLimit === void 0 ?
|
|
13628
|
+
return statementLimit === void 0 ? limit2 : Math.min(limit2, statementLimit);
|
|
13621
13629
|
}
|
|
13622
13630
|
function warningLines(warnings, format) {
|
|
13623
13631
|
return warnings.map((w) => {
|
|
@@ -13735,7 +13743,7 @@ function outputResults(rows, fieldDescs, warnings, args5, cached, read) {
|
|
|
13735
13743
|
}
|
|
13736
13744
|
writeRows(format, rows, resultColumns(read.gaql, rows), warningLines(allWarnings, format));
|
|
13737
13745
|
}
|
|
13738
|
-
function resolveGaql(args5,
|
|
13746
|
+
function resolveGaql(args5, limit2) {
|
|
13739
13747
|
if (args5.preset) {
|
|
13740
13748
|
const preset = getPreset(args5.preset);
|
|
13741
13749
|
if (!preset) {
|
|
@@ -13748,7 +13756,7 @@ function resolveGaql(args5, limit) {
|
|
|
13748
13756
|
}
|
|
13749
13757
|
const expanded = expandPreset(preset, {
|
|
13750
13758
|
dateRange: args5["date-range"],
|
|
13751
|
-
limit,
|
|
13759
|
+
limit: limit2,
|
|
13752
13760
|
includePaused: Boolean(args5["include-paused"])
|
|
13753
13761
|
});
|
|
13754
13762
|
if (expanded.dateRangeError) {
|
|
@@ -13900,8 +13908,8 @@ async function fetchAllPages(gaql, body, args5, servingOptions) {
|
|
|
13900
13908
|
fileColumns: fileColumns ?? []
|
|
13901
13909
|
};
|
|
13902
13910
|
}
|
|
13903
|
-
async function executeQuery(finalQuery, args5, customerId,
|
|
13904
|
-
const body = { customerId, query: finalQuery, pageSize:
|
|
13911
|
+
async function executeQuery(finalQuery, args5, customerId, limit2, warnings, useCache, cacheKey) {
|
|
13912
|
+
const body = { customerId, query: finalQuery, pageSize: limit2 };
|
|
13905
13913
|
const managerId = getManagerIdForCustomer(customerId);
|
|
13906
13914
|
if (managerId) body.managerId = managerId;
|
|
13907
13915
|
if (args5.cursor) body.pageToken = args5.cursor;
|
|
@@ -13916,7 +13924,7 @@ async function executeQuery(finalQuery, args5, customerId, limit, warnings, useC
|
|
|
13916
13924
|
if (args5.out) {
|
|
13917
13925
|
const truncation = completenessWarnings({
|
|
13918
13926
|
rowCount: totalRowsWritten,
|
|
13919
|
-
effectiveLimit: effectiveRowLimit(finalQuery,
|
|
13927
|
+
effectiveLimit: effectiveRowLimit(finalQuery, limit2, Boolean(args5.all)),
|
|
13920
13928
|
all: Boolean(args5.all),
|
|
13921
13929
|
hasMore: Boolean(lastPageToken)
|
|
13922
13930
|
});
|
|
@@ -13958,7 +13966,7 @@ async function executeQuery(finalQuery, args5, customerId, limit, warnings, useC
|
|
|
13958
13966
|
false,
|
|
13959
13967
|
{
|
|
13960
13968
|
gaql: finalQuery,
|
|
13961
|
-
effectiveLimit: effectiveRowLimit(finalQuery,
|
|
13969
|
+
effectiveLimit: effectiveRowLimit(finalQuery, limit2, Boolean(args5.all)),
|
|
13962
13970
|
all: Boolean(args5.all),
|
|
13963
13971
|
nextCursor: lastPageToken
|
|
13964
13972
|
}
|
|
@@ -13970,8 +13978,8 @@ function shouldReadCache(args5) {
|
|
|
13970
13978
|
var DEFAULT_QUERY_LIMIT = 200;
|
|
13971
13979
|
function parseQueryLimit(raw) {
|
|
13972
13980
|
if (raw === void 0 || raw === null || raw === "") return { ok: true, limit: DEFAULT_QUERY_LIMIT };
|
|
13973
|
-
const
|
|
13974
|
-
if (Number.isInteger(
|
|
13981
|
+
const limit2 = Number(raw);
|
|
13982
|
+
if (Number.isInteger(limit2) && limit2 >= 1 && limit2 <= GOOGLE_ADS_QUERY_MAX_PAGE_SIZE) return { ok: true, limit: limit2 };
|
|
13975
13983
|
return {
|
|
13976
13984
|
ok: false,
|
|
13977
13985
|
error: {
|
|
@@ -13994,13 +14002,13 @@ async function validateArgs(args5) {
|
|
|
13994
14002
|
writeAdsJson(parsedLimit.error);
|
|
13995
14003
|
process.exit(1);
|
|
13996
14004
|
}
|
|
13997
|
-
const { limit } = parsedLimit;
|
|
14005
|
+
const { limit: limit2 } = parsedLimit;
|
|
13998
14006
|
const customerId = await resolveCustomerId(args5);
|
|
13999
|
-
const gaql = resolveGaql(args5,
|
|
14007
|
+
const gaql = resolveGaql(args5, limit2);
|
|
14000
14008
|
if (!gaql) {
|
|
14001
14009
|
process.exit(1);
|
|
14002
14010
|
}
|
|
14003
|
-
const preflight = validatePreflight(gaql, customerId,
|
|
14011
|
+
const preflight = validatePreflight(gaql, customerId, limit2);
|
|
14004
14012
|
if (!preflight.valid && preflight.error) {
|
|
14005
14013
|
writeAdsJson(preflight.error);
|
|
14006
14014
|
process.exit(1);
|
|
@@ -14008,7 +14016,7 @@ async function validateArgs(args5) {
|
|
|
14008
14016
|
const finalQuery = preflight.correctedQuery ?? gaql;
|
|
14009
14017
|
return {
|
|
14010
14018
|
customerId,
|
|
14011
|
-
limit,
|
|
14019
|
+
limit: limit2,
|
|
14012
14020
|
finalQuery,
|
|
14013
14021
|
warnings: [...preflight.warnings, ...servingScopeWarnings(args5, finalQuery)],
|
|
14014
14022
|
useCache: !args5["no-cache"],
|
|
@@ -14085,7 +14093,7 @@ Examples:
|
|
|
14085
14093
|
}
|
|
14086
14094
|
const validated = await validateArgs(args5);
|
|
14087
14095
|
if (!validated) return;
|
|
14088
|
-
const { customerId, limit, finalQuery, warnings, useCache, cacheKey } = validated;
|
|
14096
|
+
const { customerId, limit: limit2, finalQuery, warnings, useCache, cacheKey } = validated;
|
|
14089
14097
|
if (shouldReadCache(args5)) {
|
|
14090
14098
|
const cached = cacheGet("queries", cacheKey);
|
|
14091
14099
|
if (cached) {
|
|
@@ -14103,7 +14111,7 @@ Examples:
|
|
|
14103
14111
|
true,
|
|
14104
14112
|
{
|
|
14105
14113
|
gaql: finalQuery,
|
|
14106
|
-
effectiveLimit: effectiveRowLimit(finalQuery,
|
|
14114
|
+
effectiveLimit: effectiveRowLimit(finalQuery, limit2, Boolean(args5.all)),
|
|
14107
14115
|
all: Boolean(args5.all)
|
|
14108
14116
|
}
|
|
14109
14117
|
);
|
|
@@ -14111,7 +14119,7 @@ Examples:
|
|
|
14111
14119
|
}
|
|
14112
14120
|
}
|
|
14113
14121
|
try {
|
|
14114
|
-
await executeQuery(finalQuery, args5, customerId,
|
|
14122
|
+
await executeQuery(finalQuery, args5, customerId, limit2, warnings, useCache, cacheKey);
|
|
14115
14123
|
} catch (err) {
|
|
14116
14124
|
handleQueryError(err, finalQuery, customerId);
|
|
14117
14125
|
}
|
|
@@ -14906,8 +14914,22 @@ var ANALYTICS_EVENT_TYPES = [
|
|
|
14906
14914
|
* page, `ingest` for a third party's server — and every report that needs to
|
|
14907
14915
|
* tell them apart filters on that.
|
|
14908
14916
|
*/
|
|
14909
|
-
"custom"
|
|
14917
|
+
"custom",
|
|
14918
|
+
/**
|
|
14919
|
+
* A fact about the business that names no person — a product changed, a
|
|
14920
|
+
* variant went out of stock.
|
|
14921
|
+
*
|
|
14922
|
+
* Only a commerce door writes it (`ingestShopifyFacts`), and it is a type of
|
|
14923
|
+
* its own rather than a `custom` event with no identity for one reason:
|
|
14924
|
+
* every report that lists named events whitelists `custom`, so an
|
|
14925
|
+
* operational fact would otherwise appear in the conversion picker, the
|
|
14926
|
+
* funnel and the sends. Here it reaches the raw feed and the agents that
|
|
14927
|
+
* listen for its name, and no person-level report. The row builder blanks
|
|
14928
|
+
* every identity column on it, whatever it carried.
|
|
14929
|
+
*/
|
|
14930
|
+
"operational"
|
|
14910
14931
|
];
|
|
14932
|
+
var EVENT_ITEMS_MAX = 250;
|
|
14911
14933
|
var ANALYTICS_DEVICE_TYPES = ["desktop", "mobile", "tablet", "bot", "unknown"];
|
|
14912
14934
|
var ANALYTICS_BEACON_BATCH_MAX = 50;
|
|
14913
14935
|
|
|
@@ -17700,12 +17722,12 @@ function skipBlanks(value, at) {
|
|
|
17700
17722
|
while (value[i] === " " || value[i] === " ") i++;
|
|
17701
17723
|
return i;
|
|
17702
17724
|
}
|
|
17703
|
-
function readQuotedField(value, open,
|
|
17725
|
+
function readQuotedField(value, open, flag3) {
|
|
17704
17726
|
let text2 = "";
|
|
17705
17727
|
let j = open + 1;
|
|
17706
17728
|
while (!(value[j] === '"' && value[j + 1] !== '"')) {
|
|
17707
17729
|
if (j >= value.length) {
|
|
17708
|
-
failWriteValidation(`--${
|
|
17730
|
+
failWriteValidation(`--${flag3} has a quote with no closing quote: ${value} \u2014 ${AD_COPY_LIST_USAGE}`);
|
|
17709
17731
|
}
|
|
17710
17732
|
text2 += value[j];
|
|
17711
17733
|
j += value[j] === '"' ? 2 : 1;
|
|
@@ -17713,18 +17735,18 @@ function readQuotedField(value, open, flag2) {
|
|
|
17713
17735
|
const after = skipBlanks(value, j + 1);
|
|
17714
17736
|
if (after < value.length && value[after] !== ",") {
|
|
17715
17737
|
failWriteValidation(
|
|
17716
|
-
`--${
|
|
17738
|
+
`--${flag3}: text follows the closing quote of "${text2}" \u2014 a quoted item must end at a comma. To put a quote inside an item, double it ("") or ${AD_COPY_LIST_USAGE}`
|
|
17717
17739
|
);
|
|
17718
17740
|
}
|
|
17719
17741
|
return { text: text2, next: after + 1 };
|
|
17720
17742
|
}
|
|
17721
|
-
function splitQuotedList(value,
|
|
17743
|
+
function splitQuotedList(value, flag3) {
|
|
17722
17744
|
const fields = [];
|
|
17723
17745
|
let i = 0;
|
|
17724
17746
|
while (i <= value.length) {
|
|
17725
17747
|
const start = skipBlanks(value, i);
|
|
17726
17748
|
if (value[start] === '"') {
|
|
17727
|
-
const { text: text2, next } = readQuotedField(value, start,
|
|
17749
|
+
const { text: text2, next } = readQuotedField(value, start, flag3);
|
|
17728
17750
|
fields.push({ text: text2, quoted: true });
|
|
17729
17751
|
i = next;
|
|
17730
17752
|
} else {
|
|
@@ -17746,53 +17768,53 @@ function jsonStringArray(value) {
|
|
|
17746
17768
|
return void 0;
|
|
17747
17769
|
}
|
|
17748
17770
|
}
|
|
17749
|
-
function parseCopyList(value,
|
|
17771
|
+
function parseCopyList(value, flag3) {
|
|
17750
17772
|
let items;
|
|
17751
17773
|
if (Array.isArray(value)) {
|
|
17752
17774
|
items = value.filter((v) => typeof v === "string").map((v) => ({ text: v.trim(), splitAtComma: false }));
|
|
17753
17775
|
} else if (typeof value === "string") {
|
|
17754
17776
|
const trimmed = value.trim();
|
|
17755
17777
|
const json = jsonStringArray(trimmed);
|
|
17756
|
-
items = json ? json.map((v) => ({ text: v.trim(), splitAtComma: false })) : splitQuotedList(trimmed,
|
|
17778
|
+
items = json ? json.map((v) => ({ text: v.trim(), splitAtComma: false })) : splitQuotedList(trimmed, flag3);
|
|
17757
17779
|
} else {
|
|
17758
17780
|
return void 0;
|
|
17759
17781
|
}
|
|
17760
17782
|
const kept = items.filter((item) => item.text.length > 0);
|
|
17761
17783
|
return kept.length > 0 ? kept : void 0;
|
|
17762
17784
|
}
|
|
17763
|
-
function copyListFlag(value,
|
|
17764
|
-
return parseCopyList(value,
|
|
17785
|
+
function copyListFlag(value, flag3) {
|
|
17786
|
+
return parseCopyList(value, flag3)?.map((item) => item.text);
|
|
17765
17787
|
}
|
|
17766
|
-
function refuseDashLedValue(rawArgs,
|
|
17788
|
+
function refuseDashLedValue(rawArgs, flag3) {
|
|
17767
17789
|
for (let i = 0; i < rawArgs.length - 1; i++) {
|
|
17768
17790
|
if (rawArgs[i] === "--") return;
|
|
17769
17791
|
const value = rawArgs[i + 1];
|
|
17770
|
-
if (rawArgs[i] === `--${
|
|
17792
|
+
if (rawArgs[i] === `--${flag3}` && value?.startsWith("-")) {
|
|
17771
17793
|
failWriteValidation(
|
|
17772
|
-
`--${
|
|
17794
|
+
`--${flag3} is followed by "${value}", which starts with a dash and is read as another flag, not as copy. Join copy that starts with a dash to its flag with =: --${flag3}="${value}"`
|
|
17773
17795
|
);
|
|
17774
17796
|
}
|
|
17775
17797
|
}
|
|
17776
17798
|
}
|
|
17777
17799
|
function withRepeatedCopyFlags(args5, rawArgs) {
|
|
17778
17800
|
const out = { ...args5 };
|
|
17779
|
-
for (const
|
|
17780
|
-
refuseDashLedValue(rawArgs ?? [],
|
|
17781
|
-
const values = repeatedFlagValues(rawArgs ?? [],
|
|
17801
|
+
for (const flag3 of AD_COPY_LIST_FLAGS) {
|
|
17802
|
+
refuseDashLedValue(rawArgs ?? [], flag3);
|
|
17803
|
+
const values = repeatedFlagValues(rawArgs ?? [], flag3);
|
|
17782
17804
|
if (values.length > 1) {
|
|
17783
|
-
out[
|
|
17805
|
+
out[flag3] = values;
|
|
17784
17806
|
}
|
|
17785
17807
|
}
|
|
17786
17808
|
return out;
|
|
17787
17809
|
}
|
|
17788
17810
|
function copyListSplitHints(args5) {
|
|
17789
17811
|
const hints2 = [];
|
|
17790
|
-
for (const
|
|
17791
|
-
const items = parseCopyList(args5[
|
|
17812
|
+
for (const flag3 of AD_COPY_LIST_FLAGS) {
|
|
17813
|
+
const items = parseCopyList(args5[flag3], flag3) ?? [];
|
|
17792
17814
|
const fragments = items.filter((item, index) => index > 0 && item.splitAtComma && new RegExp("^\\p{Ll}", "u").test(item.text));
|
|
17793
17815
|
if (fragments.length > 0) {
|
|
17794
17816
|
hints2.push(
|
|
17795
|
-
`--${
|
|
17817
|
+
`--${flag3}: ${fragments.map((f) => `"${f.text}"`).join(", ")} starts in lowercase \u2014 it looks like the end of one item cut at a comma. Check the staged copy; if it was one item, fix this op in place with \`draft amend <ref>\` (the ref this response returned) rather than staging it again, which would leave the cut copy staged too \u2014 ${AD_COPY_LIST_USAGE}.`
|
|
17796
17818
|
);
|
|
17797
17819
|
}
|
|
17798
17820
|
}
|
|
@@ -18343,11 +18365,11 @@ function urlCustomParametersFromFlags(args5, rawArgs) {
|
|
|
18343
18365
|
failWriteValidation("--clear-custom-params removes every parameter \u2014 pass it OR --custom-param, not both");
|
|
18344
18366
|
}
|
|
18345
18367
|
return entries.map((entry) => {
|
|
18346
|
-
const
|
|
18347
|
-
if (
|
|
18368
|
+
const split2 = entry.indexOf("=");
|
|
18369
|
+
if (split2 <= 0) {
|
|
18348
18370
|
failWriteValidation(`--custom-param "${entry}" must be key=value (e.g. --custom-param season=summer)`);
|
|
18349
18371
|
}
|
|
18350
|
-
return { key: entry.slice(0,
|
|
18372
|
+
return { key: entry.slice(0, split2), value: entry.slice(split2 + 1) };
|
|
18351
18373
|
});
|
|
18352
18374
|
}
|
|
18353
18375
|
var geoTargetTypeArgs = {
|
|
@@ -18360,13 +18382,13 @@ var geoTargetTypeArgs = {
|
|
|
18360
18382
|
description: "How EXCLUDED locations are matched \u2014 PRESENCE (default: excludes people in the location) or PRESENCE_OR_INTEREST (also excludes people interested in it)."
|
|
18361
18383
|
}
|
|
18362
18384
|
};
|
|
18363
|
-
function enumFlag(value,
|
|
18385
|
+
function enumFlag(value, flag3, allowed) {
|
|
18364
18386
|
if (typeof value !== "string" || value.length === 0) {
|
|
18365
18387
|
return void 0;
|
|
18366
18388
|
}
|
|
18367
18389
|
const upper2 = value.toUpperCase();
|
|
18368
18390
|
if (!allowed.includes(upper2)) {
|
|
18369
|
-
failWriteValidation(`${
|
|
18391
|
+
failWriteValidation(`${flag3} must be one of ${allowed.join(" | ")}`);
|
|
18370
18392
|
}
|
|
18371
18393
|
return upper2;
|
|
18372
18394
|
}
|
|
@@ -19086,8 +19108,8 @@ var FORMAT_CONTENT_FLAGS = {
|
|
|
19086
19108
|
// same silent drop this gate exists for, on the one format that reads no flags at all.
|
|
19087
19109
|
call: []
|
|
19088
19110
|
};
|
|
19089
|
-
function formatsReading(
|
|
19090
|
-
return Object.entries(FORMAT_CONTENT_FLAGS).filter(([, flags]) => flags.includes(
|
|
19111
|
+
function formatsReading(flag3) {
|
|
19112
|
+
return Object.entries(FORMAT_CONTENT_FLAGS).filter(([, flags]) => flags.includes(flag3)).map(([format]) => format);
|
|
19091
19113
|
}
|
|
19092
19114
|
function assertFlagsFitFormat(args5, format) {
|
|
19093
19115
|
const allowed = FORMAT_CONTENT_FLAGS[format];
|
|
@@ -19095,14 +19117,14 @@ function assertFlagsFitFormat(args5, format) {
|
|
|
19095
19117
|
return;
|
|
19096
19118
|
}
|
|
19097
19119
|
const stray = Object.keys(adContentArgs).filter(
|
|
19098
|
-
(
|
|
19120
|
+
(flag3) => flag3 !== "format" && args5[flag3] !== void 0 && !allowed.includes(flag3)
|
|
19099
19121
|
);
|
|
19100
19122
|
if (stray.length === 0) {
|
|
19101
19123
|
return;
|
|
19102
19124
|
}
|
|
19103
|
-
const detail = stray.map((
|
|
19104
|
-
const elsewhere = formatsReading(
|
|
19105
|
-
return elsewhere.length > 0 ? `--${
|
|
19125
|
+
const detail = stray.map((flag3) => {
|
|
19126
|
+
const elsewhere = formatsReading(flag3);
|
|
19127
|
+
return elsewhere.length > 0 ? `--${flag3} (${elsewhere.join(" / ")})` : `--${flag3}`;
|
|
19106
19128
|
}).join(", ");
|
|
19107
19129
|
failWriteValidation(
|
|
19108
19130
|
`a ${format} ad has no ${stray.map((f) => `--${f}`).join(", ")} \u2014 passing it here would stage the change without it. Formats that take it: ${detail}. Check the format with \`baker ads google query "SELECT ad_group_ad.ad.type FROM ad_group_ad WHERE ad_group_ad.ad.id = <id>"\`.`
|
|
@@ -19181,10 +19203,10 @@ var adContentArgs = {
|
|
|
19181
19203
|
"final-url": { type: "string", description: "Comma-separated final URLs" }
|
|
19182
19204
|
};
|
|
19183
19205
|
function assertNoContentFlags(args5) {
|
|
19184
|
-
const passed = Object.keys(adContentArgs).filter((
|
|
19206
|
+
const passed = Object.keys(adContentArgs).filter((flag3) => flag3 !== "format" && args5[flag3] !== void 0);
|
|
19185
19207
|
if (passed.length > 0) {
|
|
19186
19208
|
failWriteValidation(
|
|
19187
|
-
`${passed.map((
|
|
19209
|
+
`${passed.map((flag3) => `--${flag3}`).join(", ")} only build an ad's content alongside --format (responsiveSearch | responsiveDisplay | call | app | video | demandGen | demandGenVideo) \u2014 add it, or pass --file with the complete content`
|
|
19188
19210
|
);
|
|
19189
19211
|
}
|
|
19190
19212
|
}
|
|
@@ -19907,8 +19929,8 @@ function resolveAccountIdArg2(args5) {
|
|
|
19907
19929
|
function todayIso2() {
|
|
19908
19930
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19909
19931
|
}
|
|
19910
|
-
function daysAgoIso2(
|
|
19911
|
-
return new Date(Date.now() -
|
|
19932
|
+
function daysAgoIso2(days2) {
|
|
19933
|
+
return new Date(Date.now() - days2 * DAY_MS2).toISOString().slice(0, 10);
|
|
19912
19934
|
}
|
|
19913
19935
|
function csvOrJson2(args5) {
|
|
19914
19936
|
return args5.output ?? "json";
|
|
@@ -19982,7 +20004,7 @@ function loadPatchArg2(args5) {
|
|
|
19982
20004
|
throw err;
|
|
19983
20005
|
}
|
|
19984
20006
|
}
|
|
19985
|
-
function parseMoneyFlag(amount, currency,
|
|
20007
|
+
function parseMoneyFlag(amount, currency, flag3) {
|
|
19986
20008
|
if (amount === void 0 || amount === null || amount === "") {
|
|
19987
20009
|
return void 0;
|
|
19988
20010
|
}
|
|
@@ -19990,11 +20012,11 @@ function parseMoneyFlag(amount, currency, flag2) {
|
|
|
19990
20012
|
return { amount: String(amount) };
|
|
19991
20013
|
}
|
|
19992
20014
|
if (typeof currency !== "string" || currency.length !== 3) {
|
|
19993
|
-
failWriteValidation2(`${
|
|
20015
|
+
failWriteValidation2(`${flag3} got an invalid --currency (expected a 3-letter code like EUR)`);
|
|
19994
20016
|
}
|
|
19995
20017
|
return { amount: String(amount), currencyCode: currency.toUpperCase() };
|
|
19996
20018
|
}
|
|
19997
|
-
function parseDateFlag(value,
|
|
20019
|
+
function parseDateFlag(value, flag3) {
|
|
19998
20020
|
if (value === void 0 || value === null || value === "") {
|
|
19999
20021
|
return void 0;
|
|
20000
20022
|
}
|
|
@@ -20004,11 +20026,11 @@ function parseDateFlag(value, flag2) {
|
|
|
20004
20026
|
}
|
|
20005
20027
|
const parsed = Date.parse(raw);
|
|
20006
20028
|
if (Number.isNaN(parsed)) {
|
|
20007
|
-
failWriteValidation2(`${
|
|
20029
|
+
failWriteValidation2(`${flag3} must be an ISO date (2026-07-10) or epoch milliseconds`);
|
|
20008
20030
|
}
|
|
20009
20031
|
return parsed;
|
|
20010
20032
|
}
|
|
20011
|
-
function parseOnOffFlag(value,
|
|
20033
|
+
function parseOnOffFlag(value, flag3) {
|
|
20012
20034
|
if (value === void 0 || value === null || value === "") {
|
|
20013
20035
|
return void 0;
|
|
20014
20036
|
}
|
|
@@ -20019,7 +20041,7 @@ function parseOnOffFlag(value, flag2) {
|
|
|
20019
20041
|
if (raw === "off" || raw === "false") {
|
|
20020
20042
|
return false;
|
|
20021
20043
|
}
|
|
20022
|
-
failWriteValidation2(`${
|
|
20044
|
+
failWriteValidation2(`${flag3} must be on|off`);
|
|
20023
20045
|
}
|
|
20024
20046
|
function parseLocaleFlag(value) {
|
|
20025
20047
|
if (value === void 0 || value === null || value === "") {
|
|
@@ -21205,13 +21227,13 @@ Examples:
|
|
|
21205
21227
|
}
|
|
21206
21228
|
});
|
|
21207
21229
|
}
|
|
21208
|
-
function trackingPairs(value,
|
|
21230
|
+
function trackingPairs(value, flag3) {
|
|
21209
21231
|
const raw = value === void 0 ? [] : Array.isArray(value) ? value : [value];
|
|
21210
21232
|
return raw.flatMap(
|
|
21211
21233
|
(entry) => String(entry).split("&").filter((pair) => pair.length > 0).map((pair) => {
|
|
21212
21234
|
const at = pair.indexOf("=");
|
|
21213
21235
|
if (at < 1 || at === pair.length - 1) {
|
|
21214
|
-
failWriteValidation2(`${
|
|
21236
|
+
failWriteValidation2(`${flag3} expects key=value pairs \u2014 got "${pair}"`);
|
|
21215
21237
|
}
|
|
21216
21238
|
return [pair.slice(0, at).trim(), pair.slice(at + 1).trim()];
|
|
21217
21239
|
})
|
|
@@ -21547,9 +21569,9 @@ var CREATIVE_AMEND_CONTENT_FLAGS = [
|
|
|
21547
21569
|
];
|
|
21548
21570
|
function creativeContentPatch(args5) {
|
|
21549
21571
|
const patch = {};
|
|
21550
|
-
for (const [
|
|
21551
|
-
if (args5[
|
|
21552
|
-
patch[key] = args5[
|
|
21572
|
+
for (const [flag3, key] of CREATIVE_AMEND_CONTENT_FLAGS) {
|
|
21573
|
+
if (args5[flag3] !== void 0) {
|
|
21574
|
+
patch[key] = args5[flag3];
|
|
21553
21575
|
}
|
|
21554
21576
|
}
|
|
21555
21577
|
if (args5.cta !== void 0) {
|
|
@@ -22204,11 +22226,11 @@ function resolveDateRange(args5) {
|
|
|
22204
22226
|
return { start, end };
|
|
22205
22227
|
}
|
|
22206
22228
|
const lastDaysRaw = args5["last-days"];
|
|
22207
|
-
const
|
|
22208
|
-
if (!Number.isFinite(
|
|
22229
|
+
const days2 = lastDaysRaw ? Number(lastDaysRaw) : 7;
|
|
22230
|
+
if (!Number.isFinite(days2) || days2 < 1 || days2 > 730) {
|
|
22209
22231
|
handleLinkedinError(new Error(`Invalid --last-days "${lastDaysRaw}". Use a positive number \u2264 730.`));
|
|
22210
22232
|
}
|
|
22211
|
-
return { start: daysAgoIso2(
|
|
22233
|
+
return { start: daysAgoIso2(days2), end: todayIso2() };
|
|
22212
22234
|
}
|
|
22213
22235
|
function resolveScopeIds(args5, level) {
|
|
22214
22236
|
if (level === "account") {
|
|
@@ -22336,7 +22358,7 @@ Examples \u2014 common AI questions:
|
|
|
22336
22358
|
}
|
|
22337
22359
|
const range = resolveDateRange(args5);
|
|
22338
22360
|
const metrics = commaSplit(args5.metrics);
|
|
22339
|
-
const
|
|
22361
|
+
const limit2 = args5.limit ? Number(args5.limit) : 1e3;
|
|
22340
22362
|
const request = {
|
|
22341
22363
|
level,
|
|
22342
22364
|
ids,
|
|
@@ -22346,7 +22368,7 @@ Examples \u2014 common AI questions:
|
|
|
22346
22368
|
start: range.start,
|
|
22347
22369
|
end: range.end,
|
|
22348
22370
|
granularity,
|
|
22349
|
-
limit
|
|
22371
|
+
limit: limit2
|
|
22350
22372
|
};
|
|
22351
22373
|
try {
|
|
22352
22374
|
const data = await apiPost("/api/ads/linkedin/analytics", {
|
|
@@ -23138,8 +23160,8 @@ function numberOf2(v) {
|
|
|
23138
23160
|
}
|
|
23139
23161
|
return 0;
|
|
23140
23162
|
}
|
|
23141
|
-
function topByImpressions(rows,
|
|
23142
|
-
return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0,
|
|
23163
|
+
function topByImpressions(rows, limit2) {
|
|
23164
|
+
return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0, limit2);
|
|
23143
23165
|
}
|
|
23144
23166
|
var demographicsCommand = defineCommand45({
|
|
23145
23167
|
meta: {
|
|
@@ -23230,11 +23252,11 @@ function resolveRange(args5) {
|
|
|
23230
23252
|
if (start) {
|
|
23231
23253
|
return { start, end };
|
|
23232
23254
|
}
|
|
23233
|
-
const
|
|
23234
|
-
if (!Number.isFinite(
|
|
23255
|
+
const days2 = args5["last-days"] ? Number(args5["last-days"]) : 30;
|
|
23256
|
+
if (!Number.isFinite(days2) || days2 < 1) {
|
|
23235
23257
|
handleLinkedinError(new Error("Invalid --last-days; must be a positive integer."));
|
|
23236
23258
|
}
|
|
23237
|
-
return { start: daysAgoIso2(
|
|
23259
|
+
return { start: daysAgoIso2(days2), end: todayIso2() };
|
|
23238
23260
|
}
|
|
23239
23261
|
|
|
23240
23262
|
// src/commands/ads/linkedin/draft.ts
|
|
@@ -25820,7 +25842,7 @@ function mergePayload3(file, flags) {
|
|
|
25820
25842
|
}
|
|
25821
25843
|
return merged;
|
|
25822
25844
|
}
|
|
25823
|
-
function parseMoneyFlag2(amount, currency,
|
|
25845
|
+
function parseMoneyFlag2(amount, currency, flag3) {
|
|
25824
25846
|
if (amount === void 0 || amount === null || amount === "") {
|
|
25825
25847
|
return void 0;
|
|
25826
25848
|
}
|
|
@@ -25828,11 +25850,11 @@ function parseMoneyFlag2(amount, currency, flag2) {
|
|
|
25828
25850
|
return { amount: String(amount) };
|
|
25829
25851
|
}
|
|
25830
25852
|
if (typeof currency !== "string" || currency.length !== 3) {
|
|
25831
|
-
failWriteValidation3(`${
|
|
25853
|
+
failWriteValidation3(`${flag3} got an invalid --currency (expected a 3-letter code like USD)`);
|
|
25832
25854
|
}
|
|
25833
25855
|
return { amount: String(amount), currencyCode: currency.toUpperCase() };
|
|
25834
25856
|
}
|
|
25835
|
-
function parseDateFlag2(value,
|
|
25857
|
+
function parseDateFlag2(value, flag3) {
|
|
25836
25858
|
if (value === void 0 || value === null || value === "") {
|
|
25837
25859
|
return void 0;
|
|
25838
25860
|
}
|
|
@@ -25842,7 +25864,7 @@ function parseDateFlag2(value, flag2) {
|
|
|
25842
25864
|
}
|
|
25843
25865
|
const parsed = Date.parse(raw);
|
|
25844
25866
|
if (Number.isNaN(parsed)) {
|
|
25845
|
-
failWriteValidation3(`${
|
|
25867
|
+
failWriteValidation3(`${flag3} must be an ISO date (2026-07-10) or epoch milliseconds`);
|
|
25846
25868
|
}
|
|
25847
25869
|
return parsed;
|
|
25848
25870
|
}
|
|
@@ -25856,13 +25878,13 @@ function listFlag2(value) {
|
|
|
25856
25878
|
function upper(value) {
|
|
25857
25879
|
return typeof value === "string" && value.length > 0 ? value.toUpperCase() : void 0;
|
|
25858
25880
|
}
|
|
25859
|
-
function numberFlag(value,
|
|
25881
|
+
function numberFlag(value, flag3) {
|
|
25860
25882
|
if (value === void 0 || value === null || value === "") {
|
|
25861
25883
|
return void 0;
|
|
25862
25884
|
}
|
|
25863
25885
|
const n = Number(value);
|
|
25864
25886
|
if (!Number.isFinite(n)) {
|
|
25865
|
-
failWriteValidation3(`${
|
|
25887
|
+
failWriteValidation3(`${flag3} must be a number`);
|
|
25866
25888
|
}
|
|
25867
25889
|
return n;
|
|
25868
25890
|
}
|
|
@@ -27291,8 +27313,8 @@ function shouldAutoAsync(body) {
|
|
|
27291
27313
|
return true;
|
|
27292
27314
|
}
|
|
27293
27315
|
if (body.since && body.until) {
|
|
27294
|
-
const
|
|
27295
|
-
if (
|
|
27316
|
+
const days2 = (Date.parse(body.until) - Date.parse(body.since)) / 864e5;
|
|
27317
|
+
if (days2 > 90) {
|
|
27296
27318
|
return true;
|
|
27297
27319
|
}
|
|
27298
27320
|
}
|
|
@@ -27761,14 +27783,14 @@ async function runStats(args5) {
|
|
|
27761
27783
|
if (!pixelId) {
|
|
27762
27784
|
handleMetaError(new Error("--pixel-id is required when --stats is set"));
|
|
27763
27785
|
}
|
|
27764
|
-
const
|
|
27765
|
-
if (!Number.isInteger(
|
|
27786
|
+
const days2 = args5.days ? Number(args5.days) : 7;
|
|
27787
|
+
if (!Number.isInteger(days2) || days2 <= 0 || days2 > 90) {
|
|
27766
27788
|
handleMetaError(new Error("--days must be a positive integer \u2264 90"));
|
|
27767
27789
|
}
|
|
27768
27790
|
const params2 = {
|
|
27769
27791
|
"pixel-id": pixelId,
|
|
27770
27792
|
aggregation: args5.aggregation ?? "event",
|
|
27771
|
-
"start-time": daysAgoIso(
|
|
27793
|
+
"start-time": daysAgoIso(days2),
|
|
27772
27794
|
"end-time": todayIso()
|
|
27773
27795
|
};
|
|
27774
27796
|
if (args5["no-cache"]) params2["skip-cache"] = "true";
|
|
@@ -28428,10 +28450,10 @@ function parseXMoney(value) {
|
|
|
28428
28450
|
}
|
|
28429
28451
|
return { ok: true, micros: Math.round(amount * 1e6) };
|
|
28430
28452
|
}
|
|
28431
|
-
function microsFromArg(value,
|
|
28453
|
+
function microsFromArg(value, flag3) {
|
|
28432
28454
|
const parsed = parseXMoney(value);
|
|
28433
28455
|
if (!parsed.ok) {
|
|
28434
|
-
failWriteValidation4(`${
|
|
28456
|
+
failWriteValidation4(`${flag3} ${parsed.reason}`);
|
|
28435
28457
|
}
|
|
28436
28458
|
return parsed.micros;
|
|
28437
28459
|
}
|
|
@@ -30215,14 +30237,14 @@ function resolveQueryFromArgs(args5, timeZone) {
|
|
|
30215
30237
|
granularity = args5.granularity ?? preset.granularity;
|
|
30216
30238
|
placement = args5.placement ?? preset.placement;
|
|
30217
30239
|
const requested = args5.days ? Number(args5.days) : preset.defaultDays;
|
|
30218
|
-
const
|
|
30240
|
+
const days2 = Math.min(SYNC_MAX_DAYS, Math.max(1, requested));
|
|
30219
30241
|
if (requested > SYNC_MAX_DAYS) {
|
|
30220
30242
|
hints2.push(
|
|
30221
|
-
`Sync stats cover at most ${SYNC_MAX_DAYS} days, so '${preset.name}' was shortened to the last ${
|
|
30243
|
+
`Sync stats cover at most ${SYNC_MAX_DAYS} days, so '${preset.name}' was shortened to the last ${days2}. For the full window run: baker ads x stats job --entity ${entity} --entity-ids <ids> --metric-groups ${metricGroups?.join(",")} --start-time <start> --end-time <end>`
|
|
30222
30244
|
);
|
|
30223
30245
|
}
|
|
30224
30246
|
const floor = granularity === "DAY" ? (d) => accountMidnightIso(d, timeZone) : isoHourFloor;
|
|
30225
|
-
startTime ??= floor(
|
|
30247
|
+
startTime ??= floor(days2);
|
|
30226
30248
|
endTime ??= floor(0);
|
|
30227
30249
|
}
|
|
30228
30250
|
const entityIds = parseCsv5(args5["entity-ids"]);
|
|
@@ -30920,6 +30942,48 @@ var EVENT_FIELDS = [
|
|
|
30920
30942
|
name: "properties",
|
|
30921
30943
|
need: "optional",
|
|
30922
30944
|
takes: "A flat object of strings \u2014 anything you want to break the event down by later."
|
|
30945
|
+
},
|
|
30946
|
+
{
|
|
30947
|
+
name: "items",
|
|
30948
|
+
need: "optional",
|
|
30949
|
+
takes: "What was bought, one entry per product line \u2014 for a purchase, a cart or a refund.",
|
|
30950
|
+
note: `Each line names its product by at least one of the ids below. value still carries the whole event's money. An order with more than ${EVENT_ITEMS_MAX} lines keeps the first ${EVENT_ITEMS_MAX}.`
|
|
30951
|
+
},
|
|
30952
|
+
{
|
|
30953
|
+
name: "product_id, variant_id, feed_id",
|
|
30954
|
+
need: "conditional",
|
|
30955
|
+
under: true,
|
|
30956
|
+
takes: "Your store's product id, its variant id, or the id the product has in your ads catalog. At least one per line, up to 255 characters each."
|
|
30957
|
+
},
|
|
30958
|
+
{
|
|
30959
|
+
name: "quantity",
|
|
30960
|
+
need: "optional",
|
|
30961
|
+
under: true,
|
|
30962
|
+
takes: `How many: a whole number from 1 to ${MAX_ITEM_QUANTITY.toLocaleString("en-US")}.`
|
|
30963
|
+
},
|
|
30964
|
+
{
|
|
30965
|
+
name: "price",
|
|
30966
|
+
need: "optional",
|
|
30967
|
+
under: true,
|
|
30968
|
+
takes: "The price of one unit, in the event's currency \u2014 so it needs currency. A decimal like value."
|
|
30969
|
+
},
|
|
30970
|
+
{
|
|
30971
|
+
name: "consent",
|
|
30972
|
+
need: "optional",
|
|
30973
|
+
takes: "What the person allowed, if your site asked them.",
|
|
30974
|
+
note: "Send it whenever you know it. A person who said no to marketing is still counted in your reports, and is never matched or sent to an ad platform."
|
|
30975
|
+
},
|
|
30976
|
+
{
|
|
30977
|
+
name: "analytics",
|
|
30978
|
+
need: "optional",
|
|
30979
|
+
under: true,
|
|
30980
|
+
takes: "granted or denied \u2014 whether they allowed being measured. Denied keeps the event and forgets who it was."
|
|
30981
|
+
},
|
|
30982
|
+
{
|
|
30983
|
+
name: "marketing",
|
|
30984
|
+
need: "optional",
|
|
30985
|
+
under: true,
|
|
30986
|
+
takes: "granted or denied \u2014 whether they allowed their visit to be used for advertising."
|
|
30923
30987
|
}
|
|
30924
30988
|
];
|
|
30925
30989
|
var RESPONSE_FIELDS = [
|
|
@@ -31249,7 +31313,37 @@ var ingestEventSchema = z39.strictObject({
|
|
|
31249
31313
|
* left alone: masking one would rename the field and could collide with a
|
|
31250
31314
|
* sibling.
|
|
31251
31315
|
*/
|
|
31252
|
-
properties: z39.record(z39.string(), z39.string()).nullish()
|
|
31316
|
+
properties: z39.record(z39.string(), z39.string()).nullish(),
|
|
31317
|
+
/**
|
|
31318
|
+
* What was bought, one entry per line — for a purchase, a cart, a refund.
|
|
31319
|
+
*
|
|
31320
|
+
* Flat and Meta-like for the same reason as the rest of this body: it is
|
|
31321
|
+
* Meta's `contents` (`id`, `quantity`, `item_price`) and GA4's `items`
|
|
31322
|
+
* (`item_id`, `quantity`, `price`) under one spelling a sender can map from
|
|
31323
|
+
* either. A line names what it is by any of three ids — the store's product,
|
|
31324
|
+
* its variant, or the id the product has in an ads catalog. `price` is the
|
|
31325
|
+
* *unit* price in the event's `currency`; `value` stays the whole event's
|
|
31326
|
+
* money. Structure only here; `validateItems` judges each line.
|
|
31327
|
+
*/
|
|
31328
|
+
items: z39.array(
|
|
31329
|
+
z39.strictObject({
|
|
31330
|
+
product_id: z39.string().nullish(),
|
|
31331
|
+
variant_id: z39.string().nullish(),
|
|
31332
|
+
feed_id: z39.string().nullish(),
|
|
31333
|
+
quantity: z39.union([z39.string(), z39.number()]).nullish(),
|
|
31334
|
+
price: z39.union([z39.string(), z39.number()]).nullish()
|
|
31335
|
+
})
|
|
31336
|
+
).nullish(),
|
|
31337
|
+
/**
|
|
31338
|
+
* What the person allowed, each `granted` or `denied`: `analytics` (being
|
|
31339
|
+
* measured at all) and `marketing` (being matched and sent to an ad
|
|
31340
|
+
* platform). Absent means the sender did not say. Enforced before anything
|
|
31341
|
+
* is stored — see `./consent`. `validateConsent` judges the values.
|
|
31342
|
+
*/
|
|
31343
|
+
consent: z39.strictObject({
|
|
31344
|
+
analytics: z39.string().nullish(),
|
|
31345
|
+
marketing: z39.string().nullish()
|
|
31346
|
+
}).nullish()
|
|
31253
31347
|
});
|
|
31254
31348
|
var ingestBatchSchema = z39.strictObject({
|
|
31255
31349
|
events: z39.array(ingestEventSchema).min(1).max(EVENT_INGEST_BATCH_MAX)
|
|
@@ -31455,32 +31549,32 @@ function isUsableStepNameKey(key) {
|
|
|
31455
31549
|
// src/commands/analytics/conversionArgs.ts
|
|
31456
31550
|
var ConversionArgsError = class extends Error {
|
|
31457
31551
|
};
|
|
31458
|
-
function allValues(
|
|
31552
|
+
function allValues(flag3, argv) {
|
|
31459
31553
|
const values = [];
|
|
31460
31554
|
for (let i = 0; i < argv.length; i += 1) {
|
|
31461
31555
|
const arg = argv[i];
|
|
31462
|
-
if (arg ===
|
|
31556
|
+
if (arg === flag3) {
|
|
31463
31557
|
const next = argv[i + 1];
|
|
31464
31558
|
if (next !== void 0 && !next.startsWith("--")) values.push(next);
|
|
31465
31559
|
continue;
|
|
31466
31560
|
}
|
|
31467
|
-
if (arg.startsWith(`${
|
|
31561
|
+
if (arg.startsWith(`${flag3}=`)) values.push(arg.slice(flag3.length + 1));
|
|
31468
31562
|
}
|
|
31469
31563
|
return values.map((value) => value.trim()).filter((value) => value !== "");
|
|
31470
31564
|
}
|
|
31471
|
-
function onlyOnce(value,
|
|
31565
|
+
function onlyOnce(value, flag3, argv) {
|
|
31472
31566
|
if (value === void 0) return void 0;
|
|
31473
|
-
const given = argv.filter((arg) => arg ===
|
|
31567
|
+
const given = argv.filter((arg) => arg === flag3 || arg.startsWith(`${flag3}=`)).length;
|
|
31474
31568
|
if (given > 1) {
|
|
31475
31569
|
throw new ConversionArgsError(
|
|
31476
|
-
`${
|
|
31570
|
+
`${flag3} was given ${given} times and only the last would have been used. It takes one value.`
|
|
31477
31571
|
);
|
|
31478
31572
|
}
|
|
31479
31573
|
const trimmed = String(value).trim();
|
|
31480
31574
|
return trimmed === "" ? void 0 : trimmed;
|
|
31481
31575
|
}
|
|
31482
|
-
function repeatable(
|
|
31483
|
-
const fromArgv = allValues(
|
|
31576
|
+
function repeatable(flag3, cittyValue, argv) {
|
|
31577
|
+
const fromArgv = allValues(flag3, argv);
|
|
31484
31578
|
if (fromArgv.length > 0) return fromArgv;
|
|
31485
31579
|
if (cittyValue === void 0) return [];
|
|
31486
31580
|
const trimmed = String(cittyValue).trim();
|
|
@@ -31520,11 +31614,11 @@ function checkEventKeys(eventKeys) {
|
|
|
31520
31614
|
}
|
|
31521
31615
|
function readDays(raw) {
|
|
31522
31616
|
if (raw === void 0) return void 0;
|
|
31523
|
-
const
|
|
31524
|
-
if (!Number.isFinite(
|
|
31617
|
+
const days2 = Number(raw);
|
|
31618
|
+
if (!Number.isFinite(days2) || days2 <= 0) {
|
|
31525
31619
|
throw new ConversionArgsError("--days must be a positive number of days.");
|
|
31526
31620
|
}
|
|
31527
|
-
return
|
|
31621
|
+
return days2;
|
|
31528
31622
|
}
|
|
31529
31623
|
function parseConversionsArgs(raw, argv) {
|
|
31530
31624
|
const countMode = onlyOnce(raw["count-mode"], "--count-mode", argv);
|
|
@@ -32470,8 +32564,8 @@ var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
|
|
|
32470
32564
|
function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
32471
32565
|
const set = parseSetFlags(raw, argv, now);
|
|
32472
32566
|
const remove = onlyOnce(raw.remove, "--remove", argv);
|
|
32473
|
-
const
|
|
32474
|
-
if (
|
|
32567
|
+
const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
32568
|
+
if (days2 !== void 0 && (!Number.isInteger(days2) || days2 <= 0 || days2 > 400)) {
|
|
32475
32569
|
throw new ConversionArgsError("--days must be a whole number of days, from 1 to 400.");
|
|
32476
32570
|
}
|
|
32477
32571
|
const uploads = onlyOnce(raw.uploads, "--uploads", argv);
|
|
@@ -32486,17 +32580,17 @@ function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
|
32486
32580
|
return {
|
|
32487
32581
|
...set === void 0 ? {} : { set },
|
|
32488
32582
|
...remove === void 0 ? {} : { remove },
|
|
32489
|
-
...
|
|
32583
|
+
...days2 === void 0 ? {} : { days: days2 },
|
|
32490
32584
|
...uploads === void 0 ? {} : { uploads },
|
|
32491
32585
|
...raw.failed === true ? { failedOnly: true } : {},
|
|
32492
32586
|
...raw.skipped === true ? { skippedOnly: true } : {},
|
|
32493
32587
|
full: raw.full === true
|
|
32494
32588
|
};
|
|
32495
32589
|
}
|
|
32496
|
-
function flagValueAt(argv,
|
|
32590
|
+
function flagValueAt(argv, flag3, index) {
|
|
32497
32591
|
const arg = argv[index] ?? "";
|
|
32498
|
-
if (arg ===
|
|
32499
|
-
return arg.startsWith(`${
|
|
32592
|
+
if (arg === flag3) return argv[index + 1];
|
|
32593
|
+
return arg.startsWith(`${flag3}=`) ? arg.slice(flag3.length + 1) : void 0;
|
|
32500
32594
|
}
|
|
32501
32595
|
function parseParameterArgs(argv) {
|
|
32502
32596
|
const parameters = {};
|
|
@@ -32527,7 +32621,7 @@ function parseSetFlags(raw, argv, now) {
|
|
|
32527
32621
|
"--tag": onlyOnce(raw.tag, "--tag", argv),
|
|
32528
32622
|
"--event": onlyOnce(raw.event, "--event", argv)
|
|
32529
32623
|
};
|
|
32530
|
-
const given = SET_FLAGS.filter((
|
|
32624
|
+
const given = SET_FLAGS.filter((flag3) => values[flag3] !== void 0);
|
|
32531
32625
|
const set = raw.set === true;
|
|
32532
32626
|
if (!set) {
|
|
32533
32627
|
if (given.length > 0) {
|
|
@@ -32537,7 +32631,7 @@ function parseSetFlags(raw, argv, now) {
|
|
|
32537
32631
|
}
|
|
32538
32632
|
return void 0;
|
|
32539
32633
|
}
|
|
32540
|
-
const missing = SET_FLAGS.filter((
|
|
32634
|
+
const missing = SET_FLAGS.filter((flag3) => values[flag3] === void 0);
|
|
32541
32635
|
if (missing.length > 0) {
|
|
32542
32636
|
throw new ConversionArgsError(
|
|
32543
32637
|
`--set needs ${SET_FLAGS.join(", ")}; missing ${missing.join(", ")}. Copy --tag from platforms[].tags of a plain \`baker analytics sends\`, never from memory.`
|
|
@@ -33192,15 +33286,15 @@ registerSchema({
|
|
|
33192
33286
|
description: "Where events reach Baker from a server: the client's own server door, and HubSpot events Baker reads \u2014 what each one watches and reads, and how it is doing",
|
|
33193
33287
|
args: args3
|
|
33194
33288
|
});
|
|
33195
|
-
function flagValueAt2(argv,
|
|
33289
|
+
function flagValueAt2(argv, flag3, index) {
|
|
33196
33290
|
const arg = argv[index] ?? "";
|
|
33197
|
-
if (arg ===
|
|
33198
|
-
return arg.startsWith(`${
|
|
33291
|
+
if (arg === flag3) return argv[index + 1];
|
|
33292
|
+
return arg.startsWith(`${flag3}=`) ? arg.slice(flag3.length + 1) : void 0;
|
|
33199
33293
|
}
|
|
33200
|
-
function parseRepeated(argv,
|
|
33294
|
+
function parseRepeated(argv, flag3) {
|
|
33201
33295
|
const values = [];
|
|
33202
33296
|
for (let index = 0; index < argv.length; index += 1) {
|
|
33203
|
-
const value = flagValueAt2(argv,
|
|
33297
|
+
const value = flagValueAt2(argv, flag3, index);
|
|
33204
33298
|
if (value !== void 0) values.push(value);
|
|
33205
33299
|
}
|
|
33206
33300
|
return values;
|
|
@@ -34084,10 +34178,10 @@ Examples:
|
|
|
34084
34178
|
});
|
|
34085
34179
|
process.exit(1);
|
|
34086
34180
|
}
|
|
34087
|
-
const
|
|
34181
|
+
const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
34088
34182
|
const response = await apiPost("/api/analytics/tracking", {
|
|
34089
34183
|
...platform ? { platform } : {},
|
|
34090
|
-
...
|
|
34184
|
+
...days2 !== void 0 && Number.isFinite(days2) ? { days: days2 } : {}
|
|
34091
34185
|
});
|
|
34092
34186
|
writeJsonEnvelope(response);
|
|
34093
34187
|
} catch (err) {
|
|
@@ -34318,12 +34412,12 @@ Examples:
|
|
|
34318
34412
|
args: args5,
|
|
34319
34413
|
run: async ({ args: raw }) => {
|
|
34320
34414
|
try {
|
|
34321
|
-
const
|
|
34415
|
+
const limit2 = raw.limit === void 0 ? void 0 : Number(raw.limit);
|
|
34322
34416
|
const response = await apiPost("/api/analytics/arrivals", {
|
|
34323
34417
|
...raw.mode ? { mode: String(raw.mode) } : {},
|
|
34324
34418
|
...raw.outcome ? { outcome: String(raw.outcome) } : {},
|
|
34325
34419
|
...raw.event ? { eventName: String(raw.event) } : {},
|
|
34326
|
-
...
|
|
34420
|
+
...limit2 !== void 0 && Number.isFinite(limit2) ? { limit: limit2 } : {},
|
|
34327
34421
|
...raw.full ? { full: true } : {}
|
|
34328
34422
|
});
|
|
34329
34423
|
writeJsonEnvelope(response);
|
|
@@ -34775,8 +34869,8 @@ function parseGuardrails(value) {
|
|
|
34775
34869
|
}
|
|
34776
34870
|
function buildProfilePatch(args5) {
|
|
34777
34871
|
const patch = {};
|
|
34778
|
-
for (const [
|
|
34779
|
-
const value = args5[
|
|
34872
|
+
for (const [flag3, field] of TEXT_FIELDS) {
|
|
34873
|
+
const value = args5[flag3];
|
|
34780
34874
|
if (typeof value === "string") {
|
|
34781
34875
|
Object.assign(patch, { [field]: value.trim() });
|
|
34782
34876
|
}
|
|
@@ -35632,7 +35726,7 @@ function undisambiguatedSubsets(faces) {
|
|
|
35632
35726
|
if (new Set(faces.map((face) => face.subset)).size < 2) return [];
|
|
35633
35727
|
return [...new Set(faces.filter((face) => !face.unicodeRange).map((face) => face.subset))];
|
|
35634
35728
|
}
|
|
35635
|
-
function suggestFamilies(wanted, catalogue,
|
|
35729
|
+
function suggestFamilies(wanted, catalogue, limit2 = 5) {
|
|
35636
35730
|
const key = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
35637
35731
|
const target2 = key(wanted);
|
|
35638
35732
|
if (!target2) return [];
|
|
@@ -35645,7 +35739,7 @@ function suggestFamilies(wanted, catalogue, limit = 5) {
|
|
|
35645
35739
|
const shared = words2.filter((w) => w.length > 2 && candidate.includes(w)).length;
|
|
35646
35740
|
return { family, score: shared > 0 ? 3 + (words2.length - shared) : Number.POSITIVE_INFINITY };
|
|
35647
35741
|
}).filter((c) => Number.isFinite(c.score)).sort((a, b) => a.score - b.score || a.family.localeCompare(b.family));
|
|
35648
|
-
return scored.slice(0,
|
|
35742
|
+
return scored.slice(0, limit2).map((c) => c.family);
|
|
35649
35743
|
}
|
|
35650
35744
|
function asFontsourceMeta(body) {
|
|
35651
35745
|
if (typeof body !== "object" || body === null) return null;
|
|
@@ -35782,16 +35876,16 @@ function googleFontRequests(css) {
|
|
|
35782
35876
|
}
|
|
35783
35877
|
return out;
|
|
35784
35878
|
}
|
|
35785
|
-
function resolveFetchWeights(
|
|
35786
|
-
if (
|
|
35787
|
-
return String(
|
|
35879
|
+
function resolveFetchWeights(flag3, declared) {
|
|
35880
|
+
if (flag3) {
|
|
35881
|
+
return String(flag3).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
|
|
35788
35882
|
}
|
|
35789
35883
|
return declared?.length ? declared : [400];
|
|
35790
35884
|
}
|
|
35791
35885
|
var DEFAULT_SUBSETS = ["latin"];
|
|
35792
|
-
function resolveFetchSubsets(
|
|
35793
|
-
const asked = String(
|
|
35794
|
-
const named =
|
|
35886
|
+
function resolveFetchSubsets(flag3, selfHosted) {
|
|
35887
|
+
const asked = String(flag3 ?? "").split(",").map((subset) => subset.trim()).filter(Boolean);
|
|
35888
|
+
const named = flag3 ? [...new Set(asked)] : selfHosted;
|
|
35795
35889
|
return named.length > 0 ? named : [...DEFAULT_SUBSETS];
|
|
35796
35890
|
}
|
|
35797
35891
|
function resolveFetchStyles(italic, selfHosted) {
|
|
@@ -41537,11 +41631,11 @@ function classifyAudio(volumedetect, hasAudioStream) {
|
|
|
41537
41631
|
}
|
|
41538
41632
|
var RENDER_REVIEW_UNAVAILABLE = "The render was NOT reviewed \u2014 no model gateway key in this environment. Watch it yourself before sending it on.";
|
|
41539
41633
|
var REVIEW_CONCURRENCY = 3;
|
|
41540
|
-
async function mapWithLimit(items,
|
|
41634
|
+
async function mapWithLimit(items, limit2, fn) {
|
|
41541
41635
|
const out = new Array(items.length);
|
|
41542
41636
|
let next = 0;
|
|
41543
41637
|
await Promise.all(
|
|
41544
|
-
Array.from({ length: Math.min(
|
|
41638
|
+
Array.from({ length: Math.min(limit2, items.length) }, async () => {
|
|
41545
41639
|
for (let i = next++; i < items.length; i = next++) {
|
|
41546
41640
|
out[i] = await fn(items[i]);
|
|
41547
41641
|
}
|
|
@@ -42864,8 +42958,8 @@ async function resolveCastAvatar(handle) {
|
|
|
42864
42958
|
};
|
|
42865
42959
|
}
|
|
42866
42960
|
}
|
|
42867
|
-
async function resolveCastAvatars(
|
|
42868
|
-
const handles = String(
|
|
42961
|
+
async function resolveCastAvatars(flag3) {
|
|
42962
|
+
const handles = String(flag3 ?? "").split(",").map((h) => h.trim()).filter(Boolean);
|
|
42869
42963
|
const avatars = [];
|
|
42870
42964
|
for (const handle of handles) {
|
|
42871
42965
|
const resolved = await resolveCastAvatar(handle);
|
|
@@ -42978,7 +43072,7 @@ function fail3(code, message) {
|
|
|
42978
43072
|
process.exit(2);
|
|
42979
43073
|
}
|
|
42980
43074
|
function resolveModels(args5) {
|
|
42981
|
-
const pick = (
|
|
43075
|
+
const pick = (flag3, kind, fallback) => args5[flag3] ? String(args5[flag3]) : resolveModel(kind, fallback);
|
|
42982
43076
|
return {
|
|
42983
43077
|
describeModel: pick("describe-model", "image_describe", "~google/gemini-pro-latest"),
|
|
42984
43078
|
selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
|
|
@@ -42996,13 +43090,13 @@ var PLATFORM_PLACEMENTS = {
|
|
|
42996
43090
|
other: void 0
|
|
42997
43091
|
};
|
|
42998
43092
|
function resolvePlacements(placementsFlag, definitionPlatform) {
|
|
42999
|
-
const
|
|
43000
|
-
if (
|
|
43001
|
-
if (
|
|
43002
|
-
if (AD_FORMAT_PLATFORMS.includes(
|
|
43093
|
+
const flag3 = placementsFlag?.trim();
|
|
43094
|
+
if (flag3 === void 0 || flag3 === "") return { ok: true, placements: PLATFORM_PLACEMENTS[definitionPlatform] };
|
|
43095
|
+
if (flag3 === "none") return { ok: true, placements: void 0 };
|
|
43096
|
+
if (AD_FORMAT_PLATFORMS.includes(flag3)) return { ok: true, placements: flag3 };
|
|
43003
43097
|
return {
|
|
43004
43098
|
ok: false,
|
|
43005
|
-
message: `--placements "${
|
|
43099
|
+
message: `--placements "${flag3}" is not a valid placement set. Use one of: ${AD_FORMAT_PLATFORMS.join(", ")}, or "none" for a single base ad.`
|
|
43006
43100
|
};
|
|
43007
43101
|
}
|
|
43008
43102
|
function regionCount(layout) {
|
|
@@ -45017,7 +45111,7 @@ function parseBudget(raw) {
|
|
|
45017
45111
|
throw new Error(`--budget must be one of ${VIDEO_BUDGETS.join(", ")} (got "${v}")`);
|
|
45018
45112
|
}
|
|
45019
45113
|
function resolveModels2(args5) {
|
|
45020
|
-
const pick = (
|
|
45114
|
+
const pick = (flag3, kind, fallback) => args5[flag3] ? String(args5[flag3]) : resolveModel2(kind, fallback);
|
|
45021
45115
|
return {
|
|
45022
45116
|
// Flash by default: ~2-3× faster per call than Pro, which keeps each
|
|
45023
45117
|
// per-scene deconstruct step well inside the action time budget and turns a
|
|
@@ -45792,9 +45886,9 @@ var listCommand13 = defineCommand121({
|
|
|
45792
45886
|
}
|
|
45793
45887
|
body.status = args5.status;
|
|
45794
45888
|
}
|
|
45795
|
-
const
|
|
45796
|
-
if (
|
|
45797
|
-
body.limit =
|
|
45889
|
+
const limit2 = parseBoundedInt(args5.limit, "limit", 1, 100);
|
|
45890
|
+
if (limit2 !== void 0) {
|
|
45891
|
+
body.limit = limit2;
|
|
45798
45892
|
}
|
|
45799
45893
|
if (args5.full) {
|
|
45800
45894
|
body.full = true;
|
|
@@ -45891,9 +45985,9 @@ var transcriptCommand = defineCommand121({
|
|
|
45891
45985
|
run: async ({ args: args5 }) => {
|
|
45892
45986
|
try {
|
|
45893
45987
|
const body = { chatId: args5.id };
|
|
45894
|
-
const
|
|
45895
|
-
if (
|
|
45896
|
-
body.limit =
|
|
45988
|
+
const limit2 = parseBoundedInt(args5.limit, "limit", 1, 1e3);
|
|
45989
|
+
if (limit2 !== void 0) {
|
|
45990
|
+
body.limit = limit2;
|
|
45897
45991
|
}
|
|
45898
45992
|
if (args5.full) {
|
|
45899
45993
|
body.full = true;
|
|
@@ -46692,12 +46786,12 @@ function count(value, unit) {
|
|
|
46692
46786
|
return `about ${value} ${unit}${value === 1 ? "" : "s"}`;
|
|
46693
46787
|
}
|
|
46694
46788
|
function describeWait(earliestDecisionAt, now) {
|
|
46695
|
-
const
|
|
46696
|
-
if (
|
|
46697
|
-
if (
|
|
46698
|
-
if (
|
|
46699
|
-
if (
|
|
46700
|
-
return count(Math.round(
|
|
46789
|
+
const days2 = (earliestDecisionAt - now) / DAY_MS5;
|
|
46790
|
+
if (days2 <= 0) return "any moment now";
|
|
46791
|
+
if (days2 < 1) return "within a day";
|
|
46792
|
+
if (days2 < 14) return count(Math.round(days2), "day");
|
|
46793
|
+
if (days2 < 60) return count(Math.round(days2 / 7), "week");
|
|
46794
|
+
return count(Math.round(days2 / 30), "month");
|
|
46701
46795
|
}
|
|
46702
46796
|
function roughCount(count2) {
|
|
46703
46797
|
if (count2 < 10) return `about ${Math.max(1, Math.round(count2)).toLocaleString("en-US")}`;
|
|
@@ -47839,12 +47933,12 @@ var historyCommand = defineCommand124({
|
|
|
47839
47933
|
limit: { type: "string", description: "At most this many, newest first", required: false }
|
|
47840
47934
|
},
|
|
47841
47935
|
run: async ({ args: args5 }) => {
|
|
47842
|
-
const
|
|
47843
|
-
if (
|
|
47936
|
+
const limit2 = args5.limit === void 0 ? void 0 : Number(args5.limit);
|
|
47937
|
+
if (limit2 !== void 0 && !(Number.isInteger(limit2) && limit2 > 0)) fail5("`--limit` is a whole number above zero");
|
|
47844
47938
|
try {
|
|
47845
47939
|
const response = await apiPost("/api/experiments/history", {
|
|
47846
47940
|
...args5.landing ? { landingSlug: String(args5.landing) } : {},
|
|
47847
|
-
...
|
|
47941
|
+
...limit2 === void 0 ? {} : { limit: limit2 }
|
|
47848
47942
|
});
|
|
47849
47943
|
writeJsonEnvelope({
|
|
47850
47944
|
ok: true,
|
|
@@ -50325,8 +50419,8 @@ function parseFunnelArgs(raw) {
|
|
|
50325
50419
|
"Give one of --steps, --step, --remove-step, --preset, --add-trigger or --remove-trigger, not two."
|
|
50326
50420
|
);
|
|
50327
50421
|
}
|
|
50328
|
-
const
|
|
50329
|
-
if (
|
|
50422
|
+
const days2 = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
50423
|
+
if (days2 !== void 0 && (!Number.isInteger(days2) || days2 <= 0 || days2 > 400)) {
|
|
50330
50424
|
throw new FunnelArgsError("--days must be a whole number of days, from 1 to 400.");
|
|
50331
50425
|
}
|
|
50332
50426
|
return {
|
|
@@ -50338,7 +50432,7 @@ function parseFunnelArgs(raw) {
|
|
|
50338
50432
|
...removeTrigger === void 0 ? {} : { removeTrigger },
|
|
50339
50433
|
templates: raw.templates === true,
|
|
50340
50434
|
moments: raw.moments === true,
|
|
50341
|
-
...
|
|
50435
|
+
...days2 === void 0 ? {} : { days: days2 }
|
|
50342
50436
|
};
|
|
50343
50437
|
}
|
|
50344
50438
|
function funnelWrite(args5) {
|
|
@@ -50458,19 +50552,19 @@ function parsePreset(raw) {
|
|
|
50458
50552
|
}
|
|
50459
50553
|
return raw;
|
|
50460
50554
|
}
|
|
50461
|
-
function parseWayIn(stepKey, eventKey,
|
|
50555
|
+
function parseWayIn(stepKey, eventKey, flag3) {
|
|
50462
50556
|
if (stepKey === void 0) return void 0;
|
|
50463
50557
|
if (typeof stepKey !== "string" || stepKey.trim() === "") {
|
|
50464
|
-
throw new FunnelArgsError(`${
|
|
50558
|
+
throw new FunnelArgsError(`${flag3} takes the key of the step to change: \`${flag3} lead\`.`);
|
|
50465
50559
|
}
|
|
50466
50560
|
if (typeof eventKey !== "string" || eventKey.trim() === "") {
|
|
50467
|
-
throw new FunnelArgsError(`${
|
|
50561
|
+
throw new FunnelArgsError(`${flag3} needs --event, naming what gets somebody there.`, {
|
|
50468
50562
|
action: "read_the_moments",
|
|
50469
|
-
explanation: `Run \`baker funnel --moments\` and copy an \`events[].eventKey\` \u2014 a Form's own outcome is listed there at zero before anybody has filled it in. Then: \`${
|
|
50563
|
+
explanation: `Run \`baker funnel --moments\` and copy an \`events[].eventKey\` \u2014 a Form's own outcome is listed there at zero before anybody has filled it in. Then: \`${flag3} ${stepKey.trim()} --event "<key>"\`.`
|
|
50470
50564
|
});
|
|
50471
50565
|
}
|
|
50472
50566
|
const key = eventKey.trim();
|
|
50473
|
-
if (
|
|
50567
|
+
if (flag3 === "--add-trigger" && parseEventKey(key) === null) {
|
|
50474
50568
|
throw new FunnelArgsError(`"${key}" is not an event key, so nothing would ever reach that step through it.`, {
|
|
50475
50569
|
action: "read_the_moments",
|
|
50476
50570
|
explanation: "Run `baker funnel --moments` and copy an `events[].eventKey`. They look like form:<form>:<step>:<trigger>, submit:<form>, page:<name> or view:<landing>."
|
|
@@ -50513,7 +50607,7 @@ var args4 = {
|
|
|
50513
50607
|
},
|
|
50514
50608
|
preset: {
|
|
50515
50609
|
type: "string",
|
|
50516
|
-
description:
|
|
50610
|
+
description: `Draw one of the ready-made graphs instead of stating steps: b2b_sales, b2b_inbound, saas_self_serve, saas_sales_assisted, ecommerce_purchase. It draws over the whole funnel \u2014 every company already has one, so prefer --step to change a step. Run --templates first to see what each one contains. With a Shopify store connected, ecommerce_purchase comes wired to the store's own events (page:view_item, page:add_to_cart, page:begin_checkout, and page:purchase for a paid order); "Ordered again" stays unwired`,
|
|
50517
50611
|
required: false
|
|
50518
50612
|
},
|
|
50519
50613
|
moments: {
|
|
@@ -50736,29 +50830,29 @@ function requireTarget5(args5, entity) {
|
|
|
50736
50830
|
}
|
|
50737
50831
|
return target2;
|
|
50738
50832
|
}
|
|
50739
|
-
function readJsonSource(args5,
|
|
50740
|
-
const inline = args5[
|
|
50833
|
+
function readJsonSource(args5, flag3) {
|
|
50834
|
+
const inline = args5[flag3];
|
|
50741
50835
|
const file = args5.file;
|
|
50742
50836
|
const raw = typeof file === "string" && file.length > 0 ? readFileSync17(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
50743
50837
|
if (raw === void 0) {
|
|
50744
|
-
failValidation3(`pass --${
|
|
50838
|
+
failValidation3(`pass --${flag3} with inline JSON or --file with a path to a JSON file`);
|
|
50745
50839
|
}
|
|
50746
50840
|
try {
|
|
50747
50841
|
return JSON.parse(raw);
|
|
50748
50842
|
} catch {
|
|
50749
|
-
return failValidation3(`--${
|
|
50843
|
+
return failValidation3(`--${flag3} is not valid JSON`);
|
|
50750
50844
|
}
|
|
50751
50845
|
}
|
|
50752
|
-
function asObject(value,
|
|
50846
|
+
function asObject(value, flag3, index) {
|
|
50753
50847
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
50754
50848
|
failValidation3(
|
|
50755
|
-
index === void 0 ? `--${
|
|
50849
|
+
index === void 0 ? `--${flag3} must be a JSON object` : `--${flag3}[${index}] must be a JSON object`
|
|
50756
50850
|
);
|
|
50757
50851
|
}
|
|
50758
50852
|
return value;
|
|
50759
50853
|
}
|
|
50760
|
-
function loadJsonArg(args5,
|
|
50761
|
-
return asObject(readJsonSource(args5,
|
|
50854
|
+
function loadJsonArg(args5, flag3 = "json") {
|
|
50855
|
+
return asObject(readJsonSource(args5, flag3), flag3);
|
|
50762
50856
|
}
|
|
50763
50857
|
function loadJsonPayloads(args5) {
|
|
50764
50858
|
const parsed = readJsonSource(args5, "json");
|
|
@@ -51608,18 +51702,18 @@ var RETENTION_BY_MONTHS = {
|
|
|
51608
51702
|
"38": "THIRTY_EIGHT_MONTHS",
|
|
51609
51703
|
"50": "FIFTY_MONTHS"
|
|
51610
51704
|
};
|
|
51611
|
-
function retentionValue(input,
|
|
51705
|
+
function retentionValue(input, flag3) {
|
|
51612
51706
|
const normalized = input.trim();
|
|
51613
51707
|
const mapped = RETENTION_BY_MONTHS[normalized] ?? (Object.values(RETENTION_BY_MONTHS).includes(normalized.toUpperCase()) ? normalized.toUpperCase() : void 0);
|
|
51614
51708
|
if (!mapped) {
|
|
51615
|
-
failValidation3(`--${
|
|
51709
|
+
failValidation3(`--${flag3} must be one of 2, 14, 26, 38 or 50 (months)`);
|
|
51616
51710
|
}
|
|
51617
51711
|
return mapped;
|
|
51618
51712
|
}
|
|
51619
|
-
function booleanArg(input,
|
|
51713
|
+
function booleanArg(input, flag3) {
|
|
51620
51714
|
if (input === "true") return true;
|
|
51621
51715
|
if (input === "false") return false;
|
|
51622
|
-
return failValidation3(`--${
|
|
51716
|
+
return failValidation3(`--${flag3} must be true or false`);
|
|
51623
51717
|
}
|
|
51624
51718
|
var dataRetentionCommand = defineCommand136({
|
|
51625
51719
|
meta: {
|
|
@@ -51955,10 +52049,10 @@ Examples:
|
|
|
51955
52049
|
},
|
|
51956
52050
|
run: async ({ args: args5 }) => {
|
|
51957
52051
|
const payload = {};
|
|
51958
|
-
for (const [
|
|
51959
|
-
const value = args5[
|
|
52052
|
+
for (const [flag3, field] of Object.entries(MEASUREMENT_FLAGS)) {
|
|
52053
|
+
const value = args5[flag3];
|
|
51960
52054
|
if (typeof value === "string") {
|
|
51961
|
-
payload[field] = booleanArg(value,
|
|
52055
|
+
payload[field] = booleanArg(value, flag3);
|
|
51962
52056
|
}
|
|
51963
52057
|
}
|
|
51964
52058
|
if (typeof args5["search-parameters"] === "string" && args5["search-parameters"].length > 0) {
|
|
@@ -52530,13 +52624,13 @@ var listCommand15 = defineCommand142({
|
|
|
52530
52624
|
run: async ({ args: args5 }) => {
|
|
52531
52625
|
try {
|
|
52532
52626
|
const body = {};
|
|
52533
|
-
const
|
|
52534
|
-
if (
|
|
52535
|
-
body.limit =
|
|
52627
|
+
const limit2 = parseBoundedInt2(args5.limit, "limit", 1, 200);
|
|
52628
|
+
if (limit2 !== void 0) {
|
|
52629
|
+
body.limit = limit2;
|
|
52536
52630
|
}
|
|
52537
|
-
const
|
|
52538
|
-
if (
|
|
52539
|
-
body.days =
|
|
52631
|
+
const days2 = parseBoundedInt2(args5.days, "days", 1, 365);
|
|
52632
|
+
if (days2 !== void 0) {
|
|
52633
|
+
body.days = days2;
|
|
52540
52634
|
}
|
|
52541
52635
|
if (args5.category) {
|
|
52542
52636
|
if (!CATEGORIES.includes(args5.category)) {
|
|
@@ -52921,20 +53015,20 @@ var formsSubmissionsCommand = defineCommand143({
|
|
|
52921
53015
|
},
|
|
52922
53016
|
run: async ({ args: args5 }) => {
|
|
52923
53017
|
try {
|
|
52924
|
-
const
|
|
52925
|
-
if (!Number.isInteger(
|
|
53018
|
+
const days2 = args5.days === void 0 ? 30 : Number(args5.days);
|
|
53019
|
+
if (!Number.isInteger(days2) || days2 < 1 || days2 > 365) {
|
|
52926
53020
|
throw new ApiError("VALIDATION_ERROR", "--days must be a whole number between 1 and 365.");
|
|
52927
53021
|
}
|
|
52928
53022
|
const response = await apiPost("/api/hubspot/forms/submissions", {
|
|
52929
53023
|
formId: args5.formId,
|
|
52930
|
-
days,
|
|
53024
|
+
days: days2,
|
|
52931
53025
|
...args5.full ? { full: true } : {}
|
|
52932
53026
|
});
|
|
52933
53027
|
const { inWindow, total, truncated, lastSubmittedAt } = response.data;
|
|
52934
53028
|
const hints2 = [];
|
|
52935
53029
|
if (inWindow === 0) {
|
|
52936
53030
|
hints2.push(
|
|
52937
|
-
total === 0 ? "This form has received nothing at all \u2014 check it is the form actually embedded on the page before concluding the campaign is at fault." : `No leads in the last ${
|
|
53031
|
+
total === 0 ? "This form has received nothing at all \u2014 check it is the form actually embedded on the page before concluding the campaign is at fault." : `No leads in the last ${days2} days, though the form has ${total} older submission(s). It worked once and has gone quiet.`
|
|
52938
53032
|
);
|
|
52939
53033
|
}
|
|
52940
53034
|
if (truncated) {
|
|
@@ -53121,15 +53215,15 @@ var contactsSummaryCommand = defineCommand143({
|
|
|
53121
53215
|
},
|
|
53122
53216
|
run: async ({ args: args5 }) => {
|
|
53123
53217
|
try {
|
|
53124
|
-
const
|
|
53125
|
-
if (!Number.isInteger(
|
|
53218
|
+
const days2 = args5.days === void 0 ? 30 : Number(args5.days);
|
|
53219
|
+
if (!Number.isInteger(days2) || days2 < 1 || days2 > 365) {
|
|
53126
53220
|
throw new ApiError("VALIDATION_ERROR", "--days must be a whole number between 1 and 365.");
|
|
53127
53221
|
}
|
|
53128
|
-
const response = await apiPost("/api/hubspot/contacts/summary", { days });
|
|
53222
|
+
const response = await apiPost("/api/hubspot/contacts/summary", { days: days2 });
|
|
53129
53223
|
const { total, withOwner, withoutOwner, byStage, truncated } = response.data;
|
|
53130
53224
|
const hints2 = [];
|
|
53131
53225
|
if (total === 0) {
|
|
53132
|
-
hints2.push(`No contacts were created in the last ${
|
|
53226
|
+
hints2.push(`No contacts were created in the last ${days2} days \u2014 nothing reached the CRM in that window.`);
|
|
53133
53227
|
} else if (withOwner === 0) {
|
|
53134
53228
|
hints2.push(
|
|
53135
53229
|
`None of these ${total} contacts has anyone assigned. That is the strongest available signal that the leads are arriving and nobody is picking them up \u2014 worth raising with the user.`
|
|
@@ -54214,7 +54308,7 @@ function emptyResultHints({ provider, hitCount, activeFilters, subject }) {
|
|
|
54214
54308
|
return hints2;
|
|
54215
54309
|
}
|
|
54216
54310
|
function activeFilterFlags(args5, candidates) {
|
|
54217
|
-
return candidates.filter((
|
|
54311
|
+
return candidates.filter((flag3) => args5[flag3] !== void 0 && args5[flag3] !== "").map((flag3) => `--${flag3}`);
|
|
54218
54312
|
}
|
|
54219
54313
|
|
|
54220
54314
|
// src/commands/images/find.ts
|
|
@@ -58567,8 +58661,8 @@ var favoritesCommand = defineCommand174({
|
|
|
58567
58661
|
const params2 = {};
|
|
58568
58662
|
const types = splitList2(args5.type);
|
|
58569
58663
|
if (types) params2.type = types.join(",");
|
|
58570
|
-
const
|
|
58571
|
-
if (
|
|
58664
|
+
const limit2 = parseNumber(args5.limit);
|
|
58665
|
+
if (limit2 !== void 0) params2.limit = String(limit2);
|
|
58572
58666
|
const data = await apiGet("/api/landing-inspiration/favorites", params2);
|
|
58573
58667
|
const sections = Array.isArray(data?.sections) ? data.sections : [];
|
|
58574
58668
|
const full = args5.full;
|
|
@@ -60053,8 +60147,8 @@ var inPageSegment = (options) => {
|
|
|
60053
60147
|
};
|
|
60054
60148
|
const leaves = [];
|
|
60055
60149
|
const all = document.querySelectorAll("*");
|
|
60056
|
-
const
|
|
60057
|
-
for (let i = 0; i <
|
|
60150
|
+
const limit2 = Math.min(all.length, options.maxElements);
|
|
60151
|
+
for (let i = 0; i < limit2; i++) {
|
|
60058
60152
|
const element = all[i];
|
|
60059
60153
|
if (!element) continue;
|
|
60060
60154
|
const tag = element.tagName.toLowerCase();
|
|
@@ -61139,8 +61233,8 @@ function buildSearchBody(args5) {
|
|
|
61139
61233
|
if (minCraft !== void 0) body.minCraftScore = minCraft;
|
|
61140
61234
|
const minFidelity = parseNumber(args5["min-fidelity"]);
|
|
61141
61235
|
if (minFidelity !== void 0) body.minFidelity = minFidelity;
|
|
61142
|
-
const
|
|
61143
|
-
body.limit =
|
|
61236
|
+
const limit2 = parseNumber(args5.limit);
|
|
61237
|
+
body.limit = limit2 ?? 8;
|
|
61144
61238
|
body.scope = args5.scope === "all" ? "all" : "favorites";
|
|
61145
61239
|
return body;
|
|
61146
61240
|
}
|
|
@@ -61287,8 +61381,8 @@ function buildSequencesBody(args5) {
|
|
|
61287
61381
|
const sectionType = splitList2(args5["section-type"]);
|
|
61288
61382
|
if (sectionType) body.sectionType = sectionType;
|
|
61289
61383
|
body.scope = args5.scope === "all" ? "all" : "favorites";
|
|
61290
|
-
const
|
|
61291
|
-
if (
|
|
61384
|
+
const limit2 = parseNumber(args5.limit);
|
|
61385
|
+
if (limit2 !== void 0) body.limit = limit2;
|
|
61292
61386
|
else if (args5.full) body.limit = MAX_PAGES;
|
|
61293
61387
|
return body;
|
|
61294
61388
|
}
|
|
@@ -62345,7 +62439,7 @@ Examples:
|
|
|
62345
62439
|
const keyword = args5.keyword;
|
|
62346
62440
|
const location2 = args5.location || void 0;
|
|
62347
62441
|
const language = args5.language || void 0;
|
|
62348
|
-
const
|
|
62442
|
+
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
62349
62443
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
62350
62444
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
62351
62445
|
try {
|
|
@@ -62353,7 +62447,7 @@ Examples:
|
|
|
62353
62447
|
keyword,
|
|
62354
62448
|
location: location2,
|
|
62355
62449
|
language,
|
|
62356
|
-
limit,
|
|
62450
|
+
limit: limit2,
|
|
62357
62451
|
skipCache
|
|
62358
62452
|
});
|
|
62359
62453
|
warnDefaults(queryContext);
|
|
@@ -62423,7 +62517,7 @@ Examples:
|
|
|
62423
62517
|
const keyword = args5.keyword;
|
|
62424
62518
|
const location2 = args5.location || void 0;
|
|
62425
62519
|
const language = args5.language || void 0;
|
|
62426
|
-
const
|
|
62520
|
+
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
62427
62521
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
62428
62522
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
62429
62523
|
try {
|
|
@@ -62431,7 +62525,7 @@ Examples:
|
|
|
62431
62525
|
keyword,
|
|
62432
62526
|
location: location2,
|
|
62433
62527
|
language,
|
|
62434
|
-
limit,
|
|
62528
|
+
limit: limit2,
|
|
62435
62529
|
skipCache
|
|
62436
62530
|
});
|
|
62437
62531
|
warnDefaults(queryContext);
|
|
@@ -62802,7 +62896,7 @@ Examples:
|
|
|
62802
62896
|
const location2 = args5.location || void 0;
|
|
62803
62897
|
const language = args5.language || void 0;
|
|
62804
62898
|
const type = args5.type || void 0;
|
|
62805
|
-
const
|
|
62899
|
+
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
62806
62900
|
const offset = args5.offset ? Number(args5.offset) : void 0;
|
|
62807
62901
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
62808
62902
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
@@ -62813,12 +62907,12 @@ Examples:
|
|
|
62813
62907
|
location: location2,
|
|
62814
62908
|
language,
|
|
62815
62909
|
type,
|
|
62816
|
-
limit,
|
|
62910
|
+
limit: limit2,
|
|
62817
62911
|
offset,
|
|
62818
62912
|
skipCache
|
|
62819
62913
|
});
|
|
62820
62914
|
const currentOffset = offset ?? 0;
|
|
62821
|
-
const currentLimit =
|
|
62915
|
+
const currentLimit = limit2 ?? 50;
|
|
62822
62916
|
const hasMore = currentOffset + result.data.length < result.total_count;
|
|
62823
62917
|
warnDefaults(queryContext);
|
|
62824
62918
|
const format = args5.output || "json";
|
|
@@ -63071,7 +63165,7 @@ Examples:
|
|
|
63071
63165
|
const language = args5.language || void 0;
|
|
63072
63166
|
const sort = args5.sort || void 0;
|
|
63073
63167
|
const type = args5.type || void 0;
|
|
63074
|
-
const
|
|
63168
|
+
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
63075
63169
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
63076
63170
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63077
63171
|
try {
|
|
@@ -63081,7 +63175,7 @@ Examples:
|
|
|
63081
63175
|
language,
|
|
63082
63176
|
sort,
|
|
63083
63177
|
type,
|
|
63084
|
-
limit,
|
|
63178
|
+
limit: limit2,
|
|
63085
63179
|
skipCache
|
|
63086
63180
|
});
|
|
63087
63181
|
warnDefaults(queryContext);
|
|
@@ -63252,7 +63346,7 @@ Examples:
|
|
|
63252
63346
|
const target2 = args5.target;
|
|
63253
63347
|
const location2 = args5.location || void 0;
|
|
63254
63348
|
const language = args5.language || void 0;
|
|
63255
|
-
const
|
|
63349
|
+
const limit2 = args5.limit ? Number(args5.limit) : void 0;
|
|
63256
63350
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
63257
63351
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63258
63352
|
try {
|
|
@@ -63260,7 +63354,7 @@ Examples:
|
|
|
63260
63354
|
target: target2,
|
|
63261
63355
|
location: location2,
|
|
63262
63356
|
language,
|
|
63263
|
-
limit,
|
|
63357
|
+
limit: limit2,
|
|
63264
63358
|
skipCache
|
|
63265
63359
|
});
|
|
63266
63360
|
warnDefaults(queryContext);
|
|
@@ -63606,13 +63700,13 @@ function refuseMisusedKinds(kind, args5) {
|
|
|
63606
63700
|
function refuseStrayFlags(kind, args5) {
|
|
63607
63701
|
const allowed = new Set(TRIGGER_TARGETS[kind].map((target2) => TRIGGER_TARGET_FIELDS[target2.field].flag));
|
|
63608
63702
|
const stray = TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag).filter(
|
|
63609
|
-
(
|
|
63703
|
+
(flag3) => !allowed.has(flag3) && flagText(args5, flag3) !== void 0 && !(kind === "experiment.started" && flag3 === "experiment")
|
|
63610
63704
|
);
|
|
63611
63705
|
if (stray.length === 0) {
|
|
63612
63706
|
return;
|
|
63613
63707
|
}
|
|
63614
63708
|
failValidation4(
|
|
63615
|
-
`${stray.map((
|
|
63709
|
+
`${stray.map((flag3) => `--${flag3}`).join(", ")} does not narrow ${kind}. ${allowed.size > 0 ? `It can be pointed with ${[...allowed].map((flag3) => `--${flag3}`).join(", ")}.` : "It runs every time it happens \u2014 narrow it with --when rules over its payload instead."}`
|
|
63616
63710
|
);
|
|
63617
63711
|
}
|
|
63618
63712
|
var NARROWING_FLAGS = [...TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag), "config"];
|
|
@@ -63620,11 +63714,11 @@ function refuseNarrowingWithoutKind(args5, kind, given) {
|
|
|
63620
63714
|
if (kind) {
|
|
63621
63715
|
return;
|
|
63622
63716
|
}
|
|
63623
|
-
const stray = NARROWING_FLAGS.filter((
|
|
63717
|
+
const stray = NARROWING_FLAGS.filter((flag3) => flagText(args5, flag3) !== void 0);
|
|
63624
63718
|
if (stray.length === 0) {
|
|
63625
63719
|
return;
|
|
63626
63720
|
}
|
|
63627
|
-
const flags = stray.map((
|
|
63721
|
+
const flags = stray.map((flag3) => `--${flag3}`).join(", ");
|
|
63628
63722
|
failValidation4(
|
|
63629
63723
|
given > 0 ? `${flags} does not narrow --cron or --run-at: a time trigger runs every time it comes round. Use --trigger <kind> with ${flags} instead, or leave ${flags} off.` : `${flags} narrows a trigger, and no trigger was given. Pass --trigger <kind> too \u2014 the item's whole trigger, with ${flags} \u2014 or leave ${flags} off.`
|
|
63630
63724
|
);
|
|
@@ -63715,13 +63809,13 @@ var REACTION_ARGS = {
|
|
|
63715
63809
|
required: false
|
|
63716
63810
|
}
|
|
63717
63811
|
};
|
|
63718
|
-
function wholeNumber(raw,
|
|
63812
|
+
function wholeNumber(raw, flag3, { min }) {
|
|
63719
63813
|
if (raw === void 0) {
|
|
63720
63814
|
return void 0;
|
|
63721
63815
|
}
|
|
63722
63816
|
const value = Number(raw);
|
|
63723
63817
|
if (!Number.isInteger(value) || value < min) {
|
|
63724
|
-
failValidation4(`${
|
|
63818
|
+
failValidation4(`${flag3} must be a whole number of at least ${min}.`);
|
|
63725
63819
|
}
|
|
63726
63820
|
return value;
|
|
63727
63821
|
}
|
|
@@ -64191,31 +64285,31 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64191
64285
|
delete: { type: "string", description: "Remove one of this company's own, by id", required: false }
|
|
64192
64286
|
},
|
|
64193
64287
|
run: async ({ args: args5 }) => {
|
|
64194
|
-
const
|
|
64288
|
+
const flag3 = (key) => {
|
|
64195
64289
|
const value = args5[key];
|
|
64196
64290
|
return typeof value === "string" ? value.trim() : "";
|
|
64197
64291
|
};
|
|
64198
64292
|
try {
|
|
64199
|
-
const save =
|
|
64200
|
-
const publish =
|
|
64201
|
-
const remove =
|
|
64293
|
+
const save = flag3("save");
|
|
64294
|
+
const publish = flag3("publish");
|
|
64295
|
+
const remove = flag3("delete");
|
|
64202
64296
|
if ([save, publish, remove].filter((id) => id.length > 0).length > 1) {
|
|
64203
64297
|
failValidation4("Pass one of --save, --publish or --delete at a time.");
|
|
64204
64298
|
}
|
|
64205
64299
|
if (save.length > 0) {
|
|
64206
|
-
const briefFile =
|
|
64207
|
-
const brief2 = briefFile.length > 0 ? await readFile32(path46.resolve(briefFile), "utf8") :
|
|
64300
|
+
const briefFile = flag3("brief-file");
|
|
64301
|
+
const brief2 = briefFile.length > 0 ? await readFile32(path46.resolve(briefFile), "utf8") : flag3("brief");
|
|
64208
64302
|
if (brief2.trim().length === 0) {
|
|
64209
64303
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
64210
64304
|
}
|
|
64211
64305
|
const response2 = await apiPost("/api/marketplace/save", {
|
|
64212
64306
|
chatId: requireChatId(),
|
|
64213
64307
|
slug: save,
|
|
64214
|
-
name:
|
|
64215
|
-
category:
|
|
64216
|
-
tagline:
|
|
64308
|
+
name: flag3("name"),
|
|
64309
|
+
category: flag3("recipe-category"),
|
|
64310
|
+
tagline: flag3("tagline"),
|
|
64217
64311
|
prompt: brief2,
|
|
64218
|
-
frequency:
|
|
64312
|
+
frequency: flag3("frequency")
|
|
64219
64313
|
});
|
|
64220
64314
|
writeJson(response2);
|
|
64221
64315
|
return;
|
|
@@ -64236,7 +64330,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64236
64330
|
writeJson(response2);
|
|
64237
64331
|
return;
|
|
64238
64332
|
}
|
|
64239
|
-
const category =
|
|
64333
|
+
const category = flag3("category");
|
|
64240
64334
|
const response = await apiPost("/api/marketplace/list", {
|
|
64241
64335
|
...category.length > 0 ? { category } : {},
|
|
64242
64336
|
...args5.drafts === true ? { drafts: true } : {}
|
|
@@ -64528,6 +64622,150 @@ var schemaCommand2 = defineCommand208({
|
|
|
64528
64622
|
}
|
|
64529
64623
|
});
|
|
64530
64624
|
|
|
64625
|
+
// src/commands/shopify/index.ts
|
|
64626
|
+
import { defineCommand as defineCommand210 } from "citty";
|
|
64627
|
+
|
|
64628
|
+
// src/commands/shopify/buyers.ts
|
|
64629
|
+
import { defineCommand as defineCommand209 } from "citty";
|
|
64630
|
+
|
|
64631
|
+
// src/commands/shopify/buyerHints.ts
|
|
64632
|
+
var AUDIENCE_PATH = "To reach more people like your buyers on Meta, stage an audience of the store's purchasers (`baker ads meta audiences create --subtype WEBSITE`) and a lookalike of it (`--subtype LOOKALIKE`). Baker cannot upload a list of buyers to an ad platform.";
|
|
64633
|
+
var MIN_ORDERS_TO_SCALE = 5;
|
|
64634
|
+
var percent2 = (value) => `${Math.round(value * 100)}%`;
|
|
64635
|
+
function buyerHistoryHints(history, basis) {
|
|
64636
|
+
const hints2 = [];
|
|
64637
|
+
if (history.state === "importing") {
|
|
64638
|
+
hints2.push(
|
|
64639
|
+
`Baker is still bringing in this store's past orders (${history.orders} so far): older periods, repeat buyers and cohorts are incomplete \u2014 say so rather than reporting a drop.`
|
|
64640
|
+
);
|
|
64641
|
+
}
|
|
64642
|
+
if (history.state === "failed") {
|
|
64643
|
+
hints2.push("Baker couldn't finish bringing in this store's past orders; older periods may be incomplete.");
|
|
64644
|
+
}
|
|
64645
|
+
if (basis === "last_60_days") {
|
|
64646
|
+
hints2.push(
|
|
64647
|
+
"Shopify gives Baker this store's last 60 days of orders only: older behaviour is not here, and a buyer whose earlier orders are older counts as new."
|
|
64648
|
+
);
|
|
64649
|
+
}
|
|
64650
|
+
return hints2;
|
|
64651
|
+
}
|
|
64652
|
+
function countriesHints(answer) {
|
|
64653
|
+
const hints2 = buyerHistoryHints(answer.history, answer.basis);
|
|
64654
|
+
if (answer.total.orders === 0) {
|
|
64655
|
+
hints2.push("No orders were placed in this period.");
|
|
64656
|
+
return hints2;
|
|
64657
|
+
}
|
|
64658
|
+
const money = (amount) => `${answer.currency ?? ""} ${amount}`.trim();
|
|
64659
|
+
const growing = answer.rows.filter((row) => row.orders >= MIN_ORDERS_TO_SCALE && (row.ordersGrowth ?? 0) > 0).sort((a, b) => (b.ordersGrowth ?? 0) - (a.ordersGrowth ?? 0))[0];
|
|
64660
|
+
if (growing && answer.level === "country") {
|
|
64661
|
+
hints2.push(
|
|
64662
|
+
`Scale ${growing.name}: its orders grew ${percent2(growing.ordersGrowth ?? 0)} against the period before (${growing.orders} orders, ${money(growing.net)}). Check which campaigns already target it (\`baker ads meta campaigns\`, \`baker ads google query --preset campaign-performance\`) before staging a change.`
|
|
64663
|
+
);
|
|
64664
|
+
}
|
|
64665
|
+
const average = answer.total.averageOrder;
|
|
64666
|
+
const promising = answer.rows.filter((row) => row.orders < MIN_ORDERS_TO_SCALE && average > 0 && row.averageOrder >= 1.5 * average).sort((a, b) => b.averageOrder - a.averageOrder)[0];
|
|
64667
|
+
if (promising && answer.level === "country") {
|
|
64668
|
+
hints2.push(
|
|
64669
|
+
`Test ${promising.name}: its average order is ${money(promising.averageOrder)}, ${(promising.averageOrder / average).toFixed(1)}\xD7 the store's, from only ${promising.orders} orders \u2014 a small budget there would show whether it scales.`
|
|
64670
|
+
);
|
|
64671
|
+
}
|
|
64672
|
+
if (answer.unknown && answer.total.orders > 0 && answer.unknown.orders / answer.total.orders > 0.25) {
|
|
64673
|
+
hints2.push(
|
|
64674
|
+
`${answer.unknown.orders} of these orders have no address Baker could read (Unknown): say so rather than leaving them out of a country's share.`
|
|
64675
|
+
);
|
|
64676
|
+
}
|
|
64677
|
+
return hints2;
|
|
64678
|
+
}
|
|
64679
|
+
function bestSellersHints(answer) {
|
|
64680
|
+
const hints2 = buyerHistoryHints(answer.history, answer.basis);
|
|
64681
|
+
const leader = answer.repeat?.[0];
|
|
64682
|
+
if (leader && leader.buyersAgain > 0) {
|
|
64683
|
+
hints2.push(
|
|
64684
|
+
`Lead a landing with "${leader.title}" (find it with \`baker shopify products --search\`): ${percent2(leader.share)} of the buyers whose first order held it came back.`
|
|
64685
|
+
);
|
|
64686
|
+
}
|
|
64687
|
+
const top = answer.products?.[0];
|
|
64688
|
+
if (top && top.units > 0) {
|
|
64689
|
+
hints2.push(
|
|
64690
|
+
`"${top.title}" is the best seller (${top.units} units). For which first buys bring buyers back, run \`baker shopify best-sellers --view repeat\`; for what is losing steam, \`--view momentum\`.`
|
|
64691
|
+
);
|
|
64692
|
+
}
|
|
64693
|
+
const losing = answer.momentum?.[0];
|
|
64694
|
+
if (losing) {
|
|
64695
|
+
hints2.push(
|
|
64696
|
+
`"${losing.title}" sold ${losing.units} against ${losing.previousUnits} the period before: check its stock (\`baker shopify stock\`) and the ads that promote it before cutting it.`
|
|
64697
|
+
);
|
|
64698
|
+
}
|
|
64699
|
+
const refunded = answer.products?.find((row) => row.units >= 5 && row.refundRate >= 0.2);
|
|
64700
|
+
if (refunded) {
|
|
64701
|
+
hints2.push(
|
|
64702
|
+
`"${refunded.title}" comes back often (${percent2(refunded.refundRate)} of units refunded): don't lead a campaign with it before finding out why.`
|
|
64703
|
+
);
|
|
64704
|
+
}
|
|
64705
|
+
return hints2;
|
|
64706
|
+
}
|
|
64707
|
+
function bestBuyersHint(best) {
|
|
64708
|
+
if (!best || best.buyers === 0) return [];
|
|
64709
|
+
const countries = best.topCountries.map((country) => country.name).join(", ");
|
|
64710
|
+
const products = best.topFirstProducts.map((product) => `"${product.title}"`).join(", ");
|
|
64711
|
+
if (!countries && !products) return [];
|
|
64712
|
+
return [
|
|
64713
|
+
`Find more buyers like your best (${best.buyers}): ${countries ? `target ${countries}` : ""}${countries && products ? "; " : ""}${products ? `lead with ${products}, what their first orders held` : ""}.`
|
|
64714
|
+
];
|
|
64715
|
+
}
|
|
64716
|
+
function segmentsHints(answer) {
|
|
64717
|
+
const hints2 = buyerHistoryHints(answer.history, answer.basis);
|
|
64718
|
+
hints2.push(...bestBuyersHint(answer.segments.find((segment) => segment.segment === "best")));
|
|
64719
|
+
const atRisk = answer.segments.find((segment) => segment.segment === "at_risk");
|
|
64720
|
+
if (atRisk && atRisk.buyers > 0) {
|
|
64721
|
+
hints2.push(
|
|
64722
|
+
`${atRisk.buyers} repeat buyers have not ordered in ${Math.round(2 * answer.thresholds.gapDays)} days (At risk): a win-back offer to them is worth more than a new buyer of the same value.`
|
|
64723
|
+
);
|
|
64724
|
+
}
|
|
64725
|
+
if (answer.buyers > 0) hints2.push(AUDIENCE_PATH);
|
|
64726
|
+
return hints2;
|
|
64727
|
+
}
|
|
64728
|
+
function buyersHints(answer) {
|
|
64729
|
+
const hints2 = buyerHistoryHints(answer.history, answer.basis);
|
|
64730
|
+
if (answer.summary.orders === 0) {
|
|
64731
|
+
hints2.push("No orders were placed in this period.");
|
|
64732
|
+
return hints2;
|
|
64733
|
+
}
|
|
64734
|
+
if (answer.acquisition?.by === "campaign" && answer.acquisition.rows.length > 0) {
|
|
64735
|
+
hints2.push(
|
|
64736
|
+
"Compare each campaign's lifetime value with what it cost for the same dates (`baker ads meta insights`, `baker ads google query --preset campaign-performance`): Baker keeps no ad spend."
|
|
64737
|
+
);
|
|
64738
|
+
}
|
|
64739
|
+
if (!answer.acquisition) {
|
|
64740
|
+
hints2.push(
|
|
64741
|
+
"For lifetime value by the campaign or channel that brought each buyer, add `--by campaign` or `--by channel`."
|
|
64742
|
+
);
|
|
64743
|
+
}
|
|
64744
|
+
if (answer.summary.guestOrders > 0 && answer.summary.guestOrders >= answer.summary.orders / 2) {
|
|
64745
|
+
hints2.push(
|
|
64746
|
+
`${answer.summary.guestOrders} of ${answer.summary.orders} orders were placed as guests: they count in sales, never as buyers, so repeat rates read low.`
|
|
64747
|
+
);
|
|
64748
|
+
}
|
|
64749
|
+
if (answer.summary.buyers > 0) hints2.push(AUDIENCE_PATH);
|
|
64750
|
+
return hints2;
|
|
64751
|
+
}
|
|
64752
|
+
function cohortsHints(answer) {
|
|
64753
|
+
const hints2 = buyerHistoryHints(answer.history, answer.basis);
|
|
64754
|
+
const reached = answer.cohorts.filter((cohort) => cohort.retention.m3 !== null && cohort.size >= 5);
|
|
64755
|
+
if (reached.length >= 2) {
|
|
64756
|
+
const best = [...reached].sort((a, b) => (b.retention.m3 ?? 0) - (a.retention.m3 ?? 0))[0];
|
|
64757
|
+
if (best) {
|
|
64758
|
+
hints2.push(
|
|
64759
|
+
`Buyers who first ordered in ${best.month} came back best (${percent2(best.retention.m3 ?? 0)} ordered again in their third month): look at what was running then (\`baker shopify buyers --by campaign\`).`
|
|
64760
|
+
);
|
|
64761
|
+
}
|
|
64762
|
+
}
|
|
64763
|
+
return hints2;
|
|
64764
|
+
}
|
|
64765
|
+
|
|
64766
|
+
// ../api/src/shopify/buyers.ts
|
|
64767
|
+
import { z as z51 } from "zod";
|
|
64768
|
+
|
|
64531
64769
|
// ../api/src/shopify/wire.ts
|
|
64532
64770
|
import { z as z50 } from "zod";
|
|
64533
64771
|
var SHOPIFY_NOT_CONNECTED_MESSAGE = "No Shopify store is connected for this company.";
|
|
@@ -64905,9 +65143,543 @@ var shopifyStockResponseSchema = z50.object({
|
|
|
64905
65143
|
/** More products in that group than `limit`. */
|
|
64906
65144
|
more: z50.object({ outOfStock: z50.boolean(), partlyOut: z50.boolean() })
|
|
64907
65145
|
});
|
|
65146
|
+
var shopifySalesBySchema = z50.enum([
|
|
65147
|
+
"day",
|
|
65148
|
+
"product",
|
|
65149
|
+
"campaign",
|
|
65150
|
+
"landing",
|
|
65151
|
+
"weekday",
|
|
65152
|
+
"hour",
|
|
65153
|
+
"month",
|
|
65154
|
+
"month_of_year"
|
|
65155
|
+
]);
|
|
65156
|
+
var SHOPIFY_SALES_TIMING_BY = ["weekday", "hour", "month", "month_of_year"];
|
|
65157
|
+
var SHOPIFY_SALES_MAX_DAYS = 395;
|
|
65158
|
+
var SHOPIFY_SALES_TIMING_MAX_DAYS = 3650;
|
|
65159
|
+
var shopifySalesRequestSchema = z50.object({
|
|
65160
|
+
days: z50.coerce.number().int().min(1).max(SHOPIFY_SALES_TIMING_MAX_DAYS).optional(),
|
|
65161
|
+
/** Every order the store has (timing breakdowns only). */
|
|
65162
|
+
all: flag.optional(),
|
|
65163
|
+
by: shopifySalesBySchema.optional(),
|
|
65164
|
+
limit: z50.coerce.number().int().min(1).max(100).optional(),
|
|
65165
|
+
full: flag.optional()
|
|
65166
|
+
}).superRefine((request, ctx) => {
|
|
65167
|
+
if (SHOPIFY_SALES_TIMING_BY.includes(request.by ?? "day")) return;
|
|
65168
|
+
if (request.all) {
|
|
65169
|
+
ctx.addIssue({
|
|
65170
|
+
code: "custom",
|
|
65171
|
+
path: ["all"],
|
|
65172
|
+
message: "all is only for --by weekday, hour, month or month_of_year"
|
|
65173
|
+
});
|
|
65174
|
+
}
|
|
65175
|
+
if ((request.days ?? 0) > SHOPIFY_SALES_MAX_DAYS) {
|
|
65176
|
+
ctx.addIssue({
|
|
65177
|
+
code: "custom",
|
|
65178
|
+
path: ["days"],
|
|
65179
|
+
message: `by day, product, campaign or landing reads up to ${SHOPIFY_SALES_MAX_DAYS} days`
|
|
65180
|
+
});
|
|
65181
|
+
}
|
|
65182
|
+
});
|
|
65183
|
+
var shopifySalesCreditSchema = z50.enum([
|
|
65184
|
+
"campaign",
|
|
65185
|
+
"order",
|
|
65186
|
+
"landing",
|
|
65187
|
+
"before_baker",
|
|
65188
|
+
"unattributed",
|
|
65189
|
+
"other"
|
|
65190
|
+
]);
|
|
65191
|
+
var shopifySalesRowSchema = z50.object({
|
|
65192
|
+
/** A campaign, a landing's name, a day (YYYY-MM-DD) or a product's title. */
|
|
65193
|
+
label: z50.string(),
|
|
65194
|
+
credit: shopifySalesCreditSchema.optional(),
|
|
65195
|
+
orders: z50.number(),
|
|
65196
|
+
sales: z50.number(),
|
|
65197
|
+
refunded: z50.number(),
|
|
65198
|
+
net: z50.number(),
|
|
65199
|
+
/** By day: money received after the sale (an edit paid for). */
|
|
65200
|
+
added: z50.number().optional(),
|
|
65201
|
+
/** By product: units sold and given back. */
|
|
65202
|
+
units: z50.number().optional(),
|
|
65203
|
+
refundedUnits: z50.number().optional(),
|
|
65204
|
+
/** By weekday, hour or month: the buyers who ordered. */
|
|
65205
|
+
buyers: z50.number().optional(),
|
|
65206
|
+
// --full
|
|
65207
|
+
source: z50.string().optional(),
|
|
65208
|
+
medium: z50.string().optional(),
|
|
65209
|
+
campaign: z50.string().optional(),
|
|
65210
|
+
/** The ad platform of the click that brought the buyer: google, meta, linkedin, … */
|
|
65211
|
+
clickPlatform: z50.string().optional(),
|
|
65212
|
+
landingId: z50.string().optional(),
|
|
65213
|
+
productId: z50.string().optional()
|
|
65214
|
+
});
|
|
65215
|
+
var shopifySalesTotalsSchema = z50.object({
|
|
65216
|
+
orders: z50.number(),
|
|
65217
|
+
/** What the orders came to, with money added after the sale. */
|
|
65218
|
+
sales: z50.number(),
|
|
65219
|
+
added: z50.number(),
|
|
65220
|
+
refunded: z50.number(),
|
|
65221
|
+
net: z50.number()
|
|
65222
|
+
});
|
|
65223
|
+
var shopifySalesReportingSchema = z50.enum(["shopify_channel", "baker", "undecided"]);
|
|
65224
|
+
var shopifySalesResponseSchema = z50.object({
|
|
65225
|
+
store: shopifyStoreStateSchema,
|
|
65226
|
+
/** `days` is "all" with `all`; `timezone` names the store's time a timing breakdown was read in. */
|
|
65227
|
+
window: z50.object({
|
|
65228
|
+
days: z50.union([z50.number(), z50.literal("all")]),
|
|
65229
|
+
from: z50.string(),
|
|
65230
|
+
to: z50.string(),
|
|
65231
|
+
timezone: z50.string().optional()
|
|
65232
|
+
}),
|
|
65233
|
+
by: shopifySalesBySchema,
|
|
65234
|
+
/** The store's currency; null when nothing sold in the window. */
|
|
65235
|
+
currency: z50.string().nullable(),
|
|
65236
|
+
totals: shopifySalesTotalsSchema,
|
|
65237
|
+
rows: z50.array(shopifySalesRowSchema),
|
|
65238
|
+
/** Sales in another currency, which are never added to these. */
|
|
65239
|
+
otherCurrencies: z50.array(z50.object({ currency: z50.string(), net: z50.number() })).optional(),
|
|
65240
|
+
salesReporting: z50.object({ meta: shopifySalesReportingSchema, google: shopifySalesReportingSchema }),
|
|
65241
|
+
/** The order history Baker imports when a store connects: still coming in, done, or failed. */
|
|
65242
|
+
history: z50.enum(["importing", "done", "failed", "none"]),
|
|
65243
|
+
/** Baker could not read this store's orders (the store must be reconnected). */
|
|
65244
|
+
ordersUnreadable: z50.literal(true).optional()
|
|
65245
|
+
});
|
|
65246
|
+
|
|
65247
|
+
// ../api/src/shopify/buyers.ts
|
|
65248
|
+
var flag2 = z51.enum(["true", "false"]).transform((value) => value === "true");
|
|
65249
|
+
var SHOPIFY_STORE_WINDOW_MAX_DAYS = 3650;
|
|
65250
|
+
var days = z51.coerce.number().int().min(1).max(SHOPIFY_STORE_WINDOW_MAX_DAYS);
|
|
65251
|
+
var countryCode2 = z51.string().regex(/^[A-Za-z]{2}$/, "a two-letter country code, like DE").transform((value) => value.toUpperCase());
|
|
65252
|
+
var limit = z51.coerce.number().int().min(1).max(100);
|
|
65253
|
+
var windowRequest = {
|
|
65254
|
+
days: days.optional(),
|
|
65255
|
+
/** Every order the store has. */
|
|
65256
|
+
all: flag2.optional(),
|
|
65257
|
+
country: countryCode2.optional(),
|
|
65258
|
+
full: flag2.optional()
|
|
65259
|
+
};
|
|
65260
|
+
var shopifyStoreWindowSchema = z51.object({
|
|
65261
|
+
from: z51.string().nullable(),
|
|
65262
|
+
to: z51.string(),
|
|
65263
|
+
days: z51.union([z51.number(), z51.literal("all")]),
|
|
65264
|
+
timezone: z51.string()
|
|
65265
|
+
});
|
|
65266
|
+
var shopifyBuyerHistorySchema = z51.object({
|
|
65267
|
+
state: z51.enum(["importing", "done", "failed", "none"]),
|
|
65268
|
+
reach: z51.enum(["all", "60_days"]).nullable(),
|
|
65269
|
+
/** The day of the oldest order Baker holds (YYYY-MM-DD). */
|
|
65270
|
+
from: z51.string().nullable(),
|
|
65271
|
+
/** Orders brought in so far. */
|
|
65272
|
+
orders: z51.number()
|
|
65273
|
+
});
|
|
65274
|
+
var shopifyBuyerBasisSchema = z51.enum(["all_orders", "last_60_days"]);
|
|
65275
|
+
var answerCommon = {
|
|
65276
|
+
store: shopifyStoreStateSchema,
|
|
65277
|
+
window: shopifyStoreWindowSchema,
|
|
65278
|
+
/** The store's currency; null when it has no orders yet. */
|
|
65279
|
+
currency: z51.string().nullable(),
|
|
65280
|
+
/** Orders in another currency (the store changed currency), never added to these. */
|
|
65281
|
+
otherCurrencies: z51.array(z51.object({ currency: z51.string(), orders: z51.number(), net: z51.number() })).optional(),
|
|
65282
|
+
history: shopifyBuyerHistorySchema,
|
|
65283
|
+
basis: shopifyBuyerBasisSchema
|
|
65284
|
+
};
|
|
65285
|
+
var shopifyPlaceSchema = z51.object({
|
|
65286
|
+
country: z51.string(),
|
|
65287
|
+
countryName: z51.string(),
|
|
65288
|
+
region: z51.string(),
|
|
65289
|
+
city: z51.string()
|
|
65290
|
+
});
|
|
65291
|
+
var shopifyBuyerSegmentSchema = z51.enum(["best", "loyal", "at_risk", "new", "one_time"]);
|
|
65292
|
+
var shopifySegmentThresholdsSchema = z51.object({
|
|
65293
|
+
/** The store's typical days between a repeat buyer's orders (90 with too few to go on). */
|
|
65294
|
+
gapDays: z51.number(),
|
|
65295
|
+
/** The lifetime net that puts a buyer in the top fifth. */
|
|
65296
|
+
netP80: z51.number()
|
|
65297
|
+
});
|
|
65298
|
+
var shopifySegmentRowSchema = z51.object({
|
|
65299
|
+
segment: shopifyBuyerSegmentSchema,
|
|
65300
|
+
label: z51.string(),
|
|
65301
|
+
/** The rule in words, with this store's numbers. */
|
|
65302
|
+
rule: z51.string(),
|
|
65303
|
+
buyers: z51.number(),
|
|
65304
|
+
/** Of every buyer, 0–1. */
|
|
65305
|
+
share: z51.number(),
|
|
65306
|
+
net: z51.number(),
|
|
65307
|
+
averageOrders: z51.number(),
|
|
65308
|
+
averageDaysSinceLastOrder: z51.number(),
|
|
65309
|
+
topCountries: z51.array(z51.object({ code: z51.string(), name: z51.string(), buyers: z51.number() })),
|
|
65310
|
+
/** The products their first orders held most often. */
|
|
65311
|
+
topFirstProducts: z51.array(z51.object({ title: z51.string(), buyers: z51.number(), productId: z51.string().optional() }))
|
|
65312
|
+
});
|
|
65313
|
+
var shopifySegmentsRequestSchema = z51.object({ ...windowRequest });
|
|
65314
|
+
var shopifySegmentsResponseSchema = z51.object({
|
|
65315
|
+
...answerCommon,
|
|
65316
|
+
thresholds: shopifySegmentThresholdsSchema,
|
|
65317
|
+
buyers: z51.number(),
|
|
65318
|
+
segments: z51.array(shopifySegmentRowSchema)
|
|
65319
|
+
});
|
|
65320
|
+
var shopifyBuyersSortSchema = z51.enum(["net", "orders", "recent", "first"]);
|
|
65321
|
+
var shopifyAcquisitionBySchema = z51.enum(["campaign", "channel"]);
|
|
65322
|
+
var shopifyBuyersRequestSchema = z51.object({
|
|
65323
|
+
...windowRequest,
|
|
65324
|
+
segment: shopifyBuyerSegmentSchema.optional(),
|
|
65325
|
+
/** Lifetime value by the campaign or channel of each buyer's first order. */
|
|
65326
|
+
by: shopifyAcquisitionBySchema.optional(),
|
|
65327
|
+
/** Only buyers whose first order came through this channel (a key from `by=channel`). */
|
|
65328
|
+
channel: z51.string().max(200).optional(),
|
|
65329
|
+
sort: shopifyBuyersSortSchema.optional(),
|
|
65330
|
+
limit: limit.optional(),
|
|
65331
|
+
offset: z51.coerce.number().int().min(0).max(1e5).optional()
|
|
65332
|
+
});
|
|
65333
|
+
var shopifyBuyersSummarySchema = z51.object({
|
|
65334
|
+
/** Buyers who ordered in the period. */
|
|
65335
|
+
buyers: z51.number(),
|
|
65336
|
+
/** Of them, whose first order was in the period. */
|
|
65337
|
+
newBuyers: z51.number(),
|
|
65338
|
+
returningBuyers: z51.number(),
|
|
65339
|
+
/** Orders with no customer: counted in money, never a buyer. */
|
|
65340
|
+
guestOrders: z51.number(),
|
|
65341
|
+
orders: z51.number(),
|
|
65342
|
+
net: z51.number(),
|
|
65343
|
+
averageOrder: z51.number(),
|
|
65344
|
+
/** Orders that were their buyer's first, and the rest (Shopify's new vs returning). */
|
|
65345
|
+
newOrders: z51.number(),
|
|
65346
|
+
returningOrders: z51.number(),
|
|
65347
|
+
newNet: z51.number(),
|
|
65348
|
+
returningNet: z51.number(),
|
|
65349
|
+
/** Of every buyer up to the period's end, the share who ordered again (0–1). */
|
|
65350
|
+
repeatRate: z51.number(),
|
|
65351
|
+
/** Median days from a buyer's first order to their second; null when nobody ordered twice. */
|
|
65352
|
+
medianDaysToSecond: z51.number().nullable()
|
|
65353
|
+
});
|
|
65354
|
+
var shopifyCameFromSchema = z51.object({
|
|
65355
|
+
channel: z51.string(),
|
|
65356
|
+
label: z51.string(),
|
|
65357
|
+
campaign: z51.string().optional(),
|
|
65358
|
+
// --full
|
|
65359
|
+
source: z51.string().optional(),
|
|
65360
|
+
medium: z51.string().optional(),
|
|
65361
|
+
clickPlatform: z51.string().optional(),
|
|
65362
|
+
landingId: z51.string().optional()
|
|
65363
|
+
});
|
|
65364
|
+
var shopifyBuyerRowSchema = z51.object({
|
|
65365
|
+
number: z51.number(),
|
|
65366
|
+
/** "Customer #1042". */
|
|
65367
|
+
label: z51.string(),
|
|
65368
|
+
place: shopifyPlaceSchema.nullable(),
|
|
65369
|
+
orders: z51.number(),
|
|
65370
|
+
net: z51.number(),
|
|
65371
|
+
firstOrderAt: z51.string(),
|
|
65372
|
+
lastOrderAt: z51.string(),
|
|
65373
|
+
segment: shopifyBuyerSegmentSchema,
|
|
65374
|
+
cameFrom: shopifyCameFromSchema,
|
|
65375
|
+
// --full
|
|
65376
|
+
gross: z51.number().optional(),
|
|
65377
|
+
refunded: z51.number().optional(),
|
|
65378
|
+
ordersWithDiscount: z51.number().optional(),
|
|
65379
|
+
averageDaysBetweenOrders: z51.number().nullable().optional()
|
|
65380
|
+
});
|
|
65381
|
+
var shopifyAcquisitionRowSchema = z51.object({
|
|
65382
|
+
key: z51.string(),
|
|
65383
|
+
label: z51.string(),
|
|
65384
|
+
buyers: z51.number(),
|
|
65385
|
+
/** What their first orders came to. */
|
|
65386
|
+
firstNet: z51.number(),
|
|
65387
|
+
/** What they have spent since, to date. */
|
|
65388
|
+
lifetimeNet: z51.number(),
|
|
65389
|
+
lifetimePerBuyer: z51.number(),
|
|
65390
|
+
averageOrders: z51.number(),
|
|
65391
|
+
repeatRate: z51.number(),
|
|
65392
|
+
// --full
|
|
65393
|
+
source: z51.string().optional(),
|
|
65394
|
+
medium: z51.string().optional(),
|
|
65395
|
+
campaign: z51.string().optional(),
|
|
65396
|
+
clickPlatform: z51.string().optional()
|
|
65397
|
+
});
|
|
65398
|
+
var shopifyBuyersResponseSchema = z51.object({
|
|
65399
|
+
...answerCommon,
|
|
65400
|
+
summary: shopifyBuyersSummarySchema,
|
|
65401
|
+
thresholds: shopifySegmentThresholdsSchema,
|
|
65402
|
+
segments: z51.array(z51.object({ segment: shopifyBuyerSegmentSchema, label: z51.string(), buyers: z51.number() })),
|
|
65403
|
+
/** Buyers matching the filters, before the limit. */
|
|
65404
|
+
total: z51.number(),
|
|
65405
|
+
buyers: z51.array(shopifyBuyerRowSchema),
|
|
65406
|
+
acquisition: z51.object({ by: shopifyAcquisitionBySchema, rows: z51.array(shopifyAcquisitionRowSchema) }).optional()
|
|
65407
|
+
});
|
|
65408
|
+
var shopifyBuyerNumberSchema = z51.string().trim().transform((value) => value.replace(/^customer\s*/i, "").replace(/^#/, "")).pipe(z51.string().regex(/^\d+$/, "a buyer's number, like 1042 or #1042")).transform((value) => Number(value)).pipe(z51.number().int().min(1).max(4e9));
|
|
65409
|
+
var shopifyBuyerRequestSchema = z51.object({ number: shopifyBuyerNumberSchema, full: flag2.optional() });
|
|
65410
|
+
var SHOPIFY_BUYER_GONE_MESSAGE = "This buyer is no longer in Baker.";
|
|
65411
|
+
var shopifyBuyerOrderSchema = z51.object({
|
|
65412
|
+
name: z51.string(),
|
|
65413
|
+
/** When it was placed, in the store's time (YYYY-MM-DD HH:MM). */
|
|
65414
|
+
placedAt: z51.string(),
|
|
65415
|
+
net: z51.number(),
|
|
65416
|
+
gross: z51.number(),
|
|
65417
|
+
refunded: z51.number(),
|
|
65418
|
+
products: z51.array(z51.object({ title: z51.string(), quantity: z51.number() })),
|
|
65419
|
+
discountCodes: z51.array(z51.string()),
|
|
65420
|
+
place: shopifyPlaceSchema.nullable(),
|
|
65421
|
+
/** Placed before Baker measured the store: counted, credited to no campaign. */
|
|
65422
|
+
beforeBaker: z51.boolean(),
|
|
65423
|
+
// --full
|
|
65424
|
+
orderId: z51.string().optional(),
|
|
65425
|
+
items: z51.array(z51.object({ productId: z51.string(), variantId: z51.string(), quantity: z51.number(), amount: z51.number() })).optional(),
|
|
65426
|
+
refundedItems: z51.array(z51.object({ productId: z51.string(), variantId: z51.string(), quantity: z51.number(), amount: z51.number() })).optional(),
|
|
65427
|
+
cameFrom: shopifyCameFromSchema.optional()
|
|
65428
|
+
});
|
|
65429
|
+
var shopifyBuyerProfileSchema = z51.object({
|
|
65430
|
+
number: z51.number(),
|
|
65431
|
+
label: z51.string(),
|
|
65432
|
+
place: shopifyPlaceSchema.nullable(),
|
|
65433
|
+
orders: z51.number(),
|
|
65434
|
+
gross: z51.number(),
|
|
65435
|
+
refunded: z51.number(),
|
|
65436
|
+
net: z51.number(),
|
|
65437
|
+
averageOrder: z51.number(),
|
|
65438
|
+
/** Average days between their orders; null with one order. */
|
|
65439
|
+
averageDaysBetweenOrders: z51.number().nullable(),
|
|
65440
|
+
firstOrderAt: z51.string(),
|
|
65441
|
+
lastOrderAt: z51.string(),
|
|
65442
|
+
ordersWithDiscount: z51.number(),
|
|
65443
|
+
segment: shopifyBuyerSegmentSchema,
|
|
65444
|
+
segmentLabel: z51.string(),
|
|
65445
|
+
cameFrom: shopifyCameFromSchema
|
|
65446
|
+
});
|
|
65447
|
+
var shopifyBuyerResponseSchema = z51.object({
|
|
65448
|
+
...answerCommon,
|
|
65449
|
+
buyer: shopifyBuyerProfileSchema,
|
|
65450
|
+
/** Newest first. */
|
|
65451
|
+
orders: z51.array(shopifyBuyerOrderSchema),
|
|
65452
|
+
products: z51.array(
|
|
65453
|
+
z51.object({ title: z51.string(), quantity: z51.number(), orders: z51.number(), productId: z51.string().optional() })
|
|
65454
|
+
)
|
|
65455
|
+
});
|
|
65456
|
+
var shopifyCountriesRequestSchema = z51.object({
|
|
65457
|
+
...windowRequest,
|
|
65458
|
+
/** Inside one region of `country` (its code or name): its cities. */
|
|
65459
|
+
region: z51.string().max(100).optional(),
|
|
65460
|
+
/** Only orders holding this product (its id or handle); money is that product's lines. */
|
|
65461
|
+
product: z51.string().max(255).optional(),
|
|
65462
|
+
limit: limit.optional()
|
|
65463
|
+
});
|
|
65464
|
+
var shopifyPlaceRowSchema = z51.object({
|
|
65465
|
+
/** A country code, a region code (or name) or a city. */
|
|
65466
|
+
key: z51.string(),
|
|
65467
|
+
name: z51.string(),
|
|
65468
|
+
orders: z51.number(),
|
|
65469
|
+
buyers: z51.number(),
|
|
65470
|
+
newBuyers: z51.number(),
|
|
65471
|
+
net: z51.number(),
|
|
65472
|
+
averageOrder: z51.number(),
|
|
65473
|
+
/** Of the total's net, 0–1. */
|
|
65474
|
+
share: z51.number(),
|
|
65475
|
+
/** Net against the period before; null when there was none before. */
|
|
65476
|
+
growth: z51.number().nullable(),
|
|
65477
|
+
ordersGrowth: z51.number().nullable(),
|
|
65478
|
+
/** The currency its buyers paid in most. */
|
|
65479
|
+
paidIn: z51.string(),
|
|
65480
|
+
// --full
|
|
65481
|
+
previousNet: z51.number().optional(),
|
|
65482
|
+
previousOrders: z51.number().optional()
|
|
65483
|
+
});
|
|
65484
|
+
var shopifyCountriesResponseSchema = z51.object({
|
|
65485
|
+
...answerCommon,
|
|
65486
|
+
level: z51.enum(["country", "region", "city"]),
|
|
65487
|
+
country: z51.string().optional(),
|
|
65488
|
+
region: z51.string().optional(),
|
|
65489
|
+
product: z51.object({ id: z51.string(), title: z51.string() }).optional(),
|
|
65490
|
+
total: shopifyPlaceRowSchema,
|
|
65491
|
+
/** Named places, best first; with `unknown` and `other` they add up to `total`. */
|
|
65492
|
+
rows: z51.array(shopifyPlaceRowSchema),
|
|
65493
|
+
/** Orders whose address Baker could not read. Always shown, never folded into `other`. */
|
|
65494
|
+
unknown: shopifyPlaceRowSchema.nullable(),
|
|
65495
|
+
/** Places past the limit, together. */
|
|
65496
|
+
other: shopifyPlaceRowSchema.nullable()
|
|
65497
|
+
});
|
|
65498
|
+
var shopifyBestSellersViewSchema = z51.enum(["products", "variants", "trend", "together", "repeat", "momentum"]);
|
|
65499
|
+
var shopifyBestSellersSortSchema = z51.enum(["units", "revenue", "orders"]);
|
|
65500
|
+
var shopifyBestSellersRequestSchema = z51.object({
|
|
65501
|
+
...windowRequest,
|
|
65502
|
+
view: shopifyBestSellersViewSchema.optional(),
|
|
65503
|
+
sort: shopifyBestSellersSortSchema.optional(),
|
|
65504
|
+
/** Only this product (its id or handle): its variants, its trend. */
|
|
65505
|
+
product: z51.string().max(255).optional(),
|
|
65506
|
+
limit: limit.optional()
|
|
65507
|
+
});
|
|
65508
|
+
var shopifyBestSellerRowSchema = z51.object({
|
|
65509
|
+
title: z51.string(),
|
|
65510
|
+
/** The option's own title, by variant. */
|
|
65511
|
+
variantTitle: z51.string().optional(),
|
|
65512
|
+
units: z51.number(),
|
|
65513
|
+
refundedUnits: z51.number(),
|
|
65514
|
+
orders: z51.number(),
|
|
65515
|
+
buyers: z51.number(),
|
|
65516
|
+
revenue: z51.number(),
|
|
65517
|
+
refunded: z51.number(),
|
|
65518
|
+
/** Refunded units of units ordered, 0–1. */
|
|
65519
|
+
refundRate: z51.number(),
|
|
65520
|
+
/** Units against the period before; null when none sold before. */
|
|
65521
|
+
growth: z51.number().nullable(),
|
|
65522
|
+
// --full
|
|
65523
|
+
productId: z51.string().optional(),
|
|
65524
|
+
variantId: z51.string().optional(),
|
|
65525
|
+
previousUnits: z51.number().optional(),
|
|
65526
|
+
previousRevenue: z51.number().optional()
|
|
65527
|
+
});
|
|
65528
|
+
var shopifyTrendRowSchema = z51.object({
|
|
65529
|
+
/** YYYY-MM, in the store's time. */
|
|
65530
|
+
month: z51.string(),
|
|
65531
|
+
title: z51.string(),
|
|
65532
|
+
units: z51.number(),
|
|
65533
|
+
revenue: z51.number(),
|
|
65534
|
+
productId: z51.string().optional()
|
|
65535
|
+
});
|
|
65536
|
+
var shopifyTogetherRowSchema = z51.object({
|
|
65537
|
+
first: z51.string(),
|
|
65538
|
+
second: z51.string(),
|
|
65539
|
+
/** Orders holding both. */
|
|
65540
|
+
orders: z51.number(),
|
|
65541
|
+
/** Of the orders holding the first, the share that also held the second (0–1). */
|
|
65542
|
+
confidence: z51.number(),
|
|
65543
|
+
firstId: z51.string().optional(),
|
|
65544
|
+
secondId: z51.string().optional()
|
|
65545
|
+
});
|
|
65546
|
+
var shopifyRepeatRowSchema = z51.object({
|
|
65547
|
+
title: z51.string(),
|
|
65548
|
+
/** Buyers whose first order held it. */
|
|
65549
|
+
buyers: z51.number(),
|
|
65550
|
+
/** Of them, who ordered again. */
|
|
65551
|
+
buyersAgain: z51.number(),
|
|
65552
|
+
share: z51.number(),
|
|
65553
|
+
medianDaysToSecond: z51.number().nullable(),
|
|
65554
|
+
productId: z51.string().optional()
|
|
65555
|
+
});
|
|
65556
|
+
var shopifyMomentumRowSchema = z51.object({
|
|
65557
|
+
title: z51.string(),
|
|
65558
|
+
units: z51.number(),
|
|
65559
|
+
previousUnits: z51.number(),
|
|
65560
|
+
/** Units against the period before (−0.4 = 40% fewer). */
|
|
65561
|
+
change: z51.number(),
|
|
65562
|
+
revenue: z51.number(),
|
|
65563
|
+
productId: z51.string().optional()
|
|
65564
|
+
});
|
|
65565
|
+
var shopifyBestSellersResponseSchema = z51.object({
|
|
65566
|
+
...answerCommon,
|
|
65567
|
+
view: shopifyBestSellersViewSchema,
|
|
65568
|
+
sort: shopifyBestSellersSortSchema,
|
|
65569
|
+
product: z51.object({ id: z51.string(), title: z51.string() }).optional(),
|
|
65570
|
+
products: z51.array(shopifyBestSellerRowSchema).optional(),
|
|
65571
|
+
variants: z51.array(shopifyBestSellerRowSchema).optional(),
|
|
65572
|
+
trend: z51.array(shopifyTrendRowSchema).optional(),
|
|
65573
|
+
together: z51.array(shopifyTogetherRowSchema).optional(),
|
|
65574
|
+
repeat: z51.array(shopifyRepeatRowSchema).optional(),
|
|
65575
|
+
momentum: z51.array(shopifyMomentumRowSchema).optional()
|
|
65576
|
+
});
|
|
65577
|
+
var shopifyCohortsRequestSchema = z51.object({
|
|
65578
|
+
months: z51.coerce.number().int().min(3).max(36).optional(),
|
|
65579
|
+
country: countryCode2.optional(),
|
|
65580
|
+
full: flag2.optional()
|
|
65581
|
+
});
|
|
65582
|
+
var shopifyCohortMonthSchema = z51.object({
|
|
65583
|
+
/** Months since the first order: 0 is the month they first bought. */
|
|
65584
|
+
offset: z51.number(),
|
|
65585
|
+
activeBuyers: z51.number(),
|
|
65586
|
+
orders: z51.number(),
|
|
65587
|
+
net: z51.number(),
|
|
65588
|
+
/** Of the cohort, who ordered in that month (0–1). */
|
|
65589
|
+
retention: z51.number(),
|
|
65590
|
+
/** What the cohort spent up to that month, per buyer. */
|
|
65591
|
+
cumulativeNetPerBuyer: z51.number()
|
|
65592
|
+
});
|
|
65593
|
+
var shopifyCohortSchema = z51.object({
|
|
65594
|
+
/** The month of their first order, YYYY-MM in the store's time. */
|
|
65595
|
+
month: z51.string(),
|
|
65596
|
+
size: z51.number(),
|
|
65597
|
+
/** Who ordered again 1, 2, 3, 6 and 12 months after; null for a month not reached yet. */
|
|
65598
|
+
retention: z51.object({
|
|
65599
|
+
m1: z51.number().nullable(),
|
|
65600
|
+
m2: z51.number().nullable(),
|
|
65601
|
+
m3: z51.number().nullable(),
|
|
65602
|
+
m6: z51.number().nullable(),
|
|
65603
|
+
m12: z51.number().nullable()
|
|
65604
|
+
}),
|
|
65605
|
+
netPerBuyerAt12: z51.number().nullable(),
|
|
65606
|
+
// --full
|
|
65607
|
+
matrix: z51.array(shopifyCohortMonthSchema).optional()
|
|
65608
|
+
});
|
|
65609
|
+
var shopifyCohortsResponseSchema = z51.object({
|
|
65610
|
+
...answerCommon,
|
|
65611
|
+
months: z51.number(),
|
|
65612
|
+
cohorts: z51.array(shopifyCohortSchema)
|
|
65613
|
+
});
|
|
64908
65614
|
|
|
64909
|
-
// src/commands/shopify/
|
|
64910
|
-
|
|
65615
|
+
// src/commands/shopify/refusal.ts
|
|
65616
|
+
var CONTINUE2 = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else.";
|
|
65617
|
+
function shopifyRefusal(code, message) {
|
|
65618
|
+
if (code !== "NOT_FOUND") return null;
|
|
65619
|
+
if (message.includes(SHOPIFY_NOT_CONNECTED_MESSAGE)) {
|
|
65620
|
+
return {
|
|
65621
|
+
code: "NO_SHOPIFY_CONNECTION",
|
|
65622
|
+
fix: {
|
|
65623
|
+
action: "request_connection",
|
|
65624
|
+
explanation: 'AGENT INSTRUCTION: no Shopify store is connected, and only the user can connect it. Call the `request_connection` tool with { platform: "shopify", reason } \u2014 reason in their words, e.g. "so I can use your real products and prices" \u2014 and they connect it inside the chat; then run this command again. ' + CONTINUE2
|
|
65625
|
+
}
|
|
65626
|
+
};
|
|
65627
|
+
}
|
|
65628
|
+
if (message.includes(SHOPIFY_NOT_OFFERED_MESSAGE)) {
|
|
65629
|
+
return {
|
|
65630
|
+
code: "SHOPIFY_NOT_AVAILABLE",
|
|
65631
|
+
fix: {
|
|
65632
|
+
action: "continue_without",
|
|
65633
|
+
explanation: "Do not call `request_connection` for Shopify and do not tell the user to connect it: a Shopify store cannot be connected on this Baker yet. Answer from the knowledge vault and the client's own website instead (`baker images extract <store url>` for product photos, `baker research fetch <url>` for a product page), say the product facts are unverified, and finish the rest of the task."
|
|
65634
|
+
}
|
|
65635
|
+
};
|
|
65636
|
+
}
|
|
65637
|
+
return null;
|
|
65638
|
+
}
|
|
65639
|
+
|
|
65640
|
+
// src/commands/shopify/common.ts
|
|
65641
|
+
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.";
|
|
65642
|
+
function fail9(err) {
|
|
65643
|
+
if (err instanceof ApiError) {
|
|
65644
|
+
const refusal = shopifyRefusal(err.code, err.message);
|
|
65645
|
+
if (refusal) {
|
|
65646
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
65647
|
+
process.exit(1);
|
|
65648
|
+
}
|
|
65649
|
+
if (err.code === "NOT_FOUND" && err.message === SHOPIFY_BUYER_GONE_MESSAGE) {
|
|
65650
|
+
writeJson({
|
|
65651
|
+
ok: false,
|
|
65652
|
+
error: { code: err.code, message: err.message },
|
|
65653
|
+
hints: [
|
|
65654
|
+
"Their store asked Baker to erase this buyer, or they were merged into another one: say the buyer is no longer in Baker, and never guess who they were."
|
|
65655
|
+
]
|
|
65656
|
+
});
|
|
65657
|
+
process.exit(1);
|
|
65658
|
+
}
|
|
65659
|
+
if (err.code === "NOT_FOUND" && err.message.startsWith(SHOPIFY_PRODUCT_NOT_FOUND_PREFIX)) {
|
|
65660
|
+
writeJson({ ok: false, error: { code: err.code, message: err.message }, hints: [PRODUCT_NOT_FOUND_HINT] });
|
|
65661
|
+
process.exit(1);
|
|
65662
|
+
}
|
|
65663
|
+
}
|
|
65664
|
+
failApi(err);
|
|
65665
|
+
}
|
|
65666
|
+
function emit2(data, meta, hints2) {
|
|
65667
|
+
writeJson({ ok: true, data, meta, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
65668
|
+
}
|
|
65669
|
+
function params(entries) {
|
|
65670
|
+
const out = {};
|
|
65671
|
+
for (const [name, value] of Object.entries(entries)) {
|
|
65672
|
+
if (value === void 0 || value === "" || value === false) continue;
|
|
65673
|
+
out[name] = String(value);
|
|
65674
|
+
}
|
|
65675
|
+
return out;
|
|
65676
|
+
}
|
|
65677
|
+
var fullArg = {
|
|
65678
|
+
type: "boolean",
|
|
65679
|
+
description: "Everything Baker keeps, not just what answers the question",
|
|
65680
|
+
required: false,
|
|
65681
|
+
default: false
|
|
65682
|
+
};
|
|
64911
65683
|
|
|
64912
65684
|
// src/commands/shopify/hints.ts
|
|
64913
65685
|
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.';
|
|
@@ -65092,7 +65864,7 @@ function productHints(product, store) {
|
|
|
65092
65864
|
}
|
|
65093
65865
|
return hints2;
|
|
65094
65866
|
}
|
|
65095
|
-
function stockHints(answer,
|
|
65867
|
+
function stockHints(answer, limit2) {
|
|
65096
65868
|
const hints2 = [];
|
|
65097
65869
|
const any = answer.outOfStock.length > 0 || answer.partlyOut.length > 0;
|
|
65098
65870
|
const unfinished = answer.more.outOfStock || answer.more.partlyOut;
|
|
@@ -65103,9 +65875,9 @@ function stockHints(answer, limit) {
|
|
|
65103
65875
|
);
|
|
65104
65876
|
} else if (!unfinished) hints2.push("Nothing is out of stock.");
|
|
65105
65877
|
if (unfinished) {
|
|
65106
|
-
const full = answer.more.outOfStock && answer.outOfStock.length >=
|
|
65878
|
+
const full = answer.more.outOfStock && answer.outOfStock.length >= limit2 || answer.more.partlyOut && answer.partlyOut.length >= limit2;
|
|
65107
65879
|
hints2.push(
|
|
65108
|
-
full ? `More than ${
|
|
65880
|
+
full ? `More than ${limit2} products in a list; raise \`--limit\` (up to 200) or ${pageThrough}.` : `Baker didn't check every product in one go, so these lists may be missing some \u2014 don't say nothing else is out of stock; ${pageThrough}.`
|
|
65109
65881
|
);
|
|
65110
65882
|
}
|
|
65111
65883
|
const big = answer.partlyOut.find((row) => row.outOptionsMore);
|
|
@@ -65140,65 +65912,350 @@ function storeHints(summary) {
|
|
|
65140
65912
|
}
|
|
65141
65913
|
return hints2;
|
|
65142
65914
|
}
|
|
65143
|
-
|
|
65144
|
-
|
|
65145
|
-
|
|
65146
|
-
|
|
65147
|
-
|
|
65148
|
-
|
|
65149
|
-
|
|
65150
|
-
|
|
65151
|
-
|
|
65152
|
-
|
|
65153
|
-
|
|
65154
|
-
|
|
65155
|
-
};
|
|
65915
|
+
function timingHints(answer) {
|
|
65916
|
+
const peak = [...answer.rows].sort((a, b) => b.orders - a.orders)[0];
|
|
65917
|
+
if (!peak || peak.orders === 0) return [];
|
|
65918
|
+
const zone = answer.window.timezone ? `, ${answer.window.timezone}` : "";
|
|
65919
|
+
return [`Most orders are placed on ${peak.label} (store time${zone}): weight budgets and sends towards it.`];
|
|
65920
|
+
}
|
|
65921
|
+
function salesHints(answer) {
|
|
65922
|
+
const hints2 = [];
|
|
65923
|
+
if (answer.ordersUnreadable) {
|
|
65924
|
+
hints2.push(
|
|
65925
|
+
"Baker can't read this store's orders right now, so these sales may be incomplete. Ask the user to reconnect the store with `request_connection` { platform: \"shopify\" }."
|
|
65926
|
+
);
|
|
65156
65927
|
}
|
|
65157
|
-
if (
|
|
65158
|
-
|
|
65159
|
-
|
|
65160
|
-
|
|
65161
|
-
action: "continue_without",
|
|
65162
|
-
explanation: "Do not call `request_connection` for Shopify and do not tell the user to connect it: a Shopify store cannot be connected on this Baker yet. Answer from the knowledge vault and the client's own website instead (`baker images extract <store url>` for product photos, `baker research fetch <url>` for a product page), say the product facts are unverified, and finish the rest of the task."
|
|
65163
|
-
}
|
|
65164
|
-
};
|
|
65928
|
+
if (answer.history === "importing") {
|
|
65929
|
+
hints2.push(
|
|
65930
|
+
"Baker is still bringing in this store's past orders; earlier periods are incomplete \u2014 say so rather than reporting a drop."
|
|
65931
|
+
);
|
|
65165
65932
|
}
|
|
65166
|
-
|
|
65933
|
+
if (answer.totals.orders === 0) {
|
|
65934
|
+
hints2.push("No orders were paid in this period.");
|
|
65935
|
+
return hints2;
|
|
65936
|
+
}
|
|
65937
|
+
if (answer.by === "weekday" || answer.by === "hour" || answer.by === "month_of_year") {
|
|
65938
|
+
return [...hints2, ...timingHints(answer)];
|
|
65939
|
+
}
|
|
65940
|
+
const notBaker = ["meta", "google"].filter((family) => answer.salesReporting[family] !== "baker");
|
|
65941
|
+
if (notBaker.length > 0) {
|
|
65942
|
+
const names = notBaker.map((family) => family === "meta" ? "Meta" : "Google").join(" and ");
|
|
65943
|
+
hints2.push(
|
|
65944
|
+
`Baker only reports these sales; it does not send them to ${names}. A manager chooses in Brain \u2192 Store whether Baker sends them (where Shopify's own channel already reports sales, its purchase tracking has to be turned off first). Never set up a purchase send yourself.`
|
|
65945
|
+
);
|
|
65946
|
+
}
|
|
65947
|
+
const unattributed = answer.rows.filter((row) => row.credit === "unattributed").reduce((total, row) => total + row.net, 0);
|
|
65948
|
+
if ((answer.by === "campaign" || answer.by === "landing") && answer.totals.net > 0 && unattributed / answer.totals.net > 0.5) {
|
|
65949
|
+
hints2.push(
|
|
65950
|
+
"Most of these sales came from no campaign Baker found: buyers who came straight to the store, or from links without campaign tags. Say so rather than crediting them to a campaign; links with UTM tags and Baker landings make the next ones traceable."
|
|
65951
|
+
);
|
|
65952
|
+
}
|
|
65953
|
+
const leading = answer.by === "landing" ? answer.rows.find((row) => row.credit === "landing") : void 0;
|
|
65954
|
+
if (leading && leading.net > 0) {
|
|
65955
|
+
hints2.push(
|
|
65956
|
+
`"${leading.label}" brought the most sales of the Baker pages (${answer.currency ?? ""} ${leading.net}). It is the page to learn from before building the next one.`
|
|
65957
|
+
);
|
|
65958
|
+
}
|
|
65959
|
+
return hints2;
|
|
65167
65960
|
}
|
|
65168
65961
|
|
|
65169
|
-
// src/commands/shopify/
|
|
65170
|
-
var
|
|
65171
|
-
|
|
65172
|
-
|
|
65173
|
-
|
|
65174
|
-
|
|
65175
|
-
|
|
65176
|
-
|
|
65962
|
+
// src/commands/shopify/buyers.ts
|
|
65963
|
+
var PERIOD_NOTE = "Orders placed in the period, in the store's own time, with what was refunded on them since (Shopify's own reports date a refund when it happens instead, so a short period can differ by the refunds that cross its edges).";
|
|
65964
|
+
var periodArgs = {
|
|
65965
|
+
days: { type: "number", description: "The last N days, 1-3650 (default 365)", required: false },
|
|
65966
|
+
all: { type: "boolean", description: "Every order the store has", required: false, default: false },
|
|
65967
|
+
country: {
|
|
65968
|
+
type: "string",
|
|
65969
|
+
description: "Only orders to this country: its two-letter code, like DE",
|
|
65970
|
+
required: false
|
|
65971
|
+
}
|
|
65972
|
+
};
|
|
65973
|
+
var periodFlags = {
|
|
65974
|
+
days: { type: "string", description: "The last N days, 1-3650 (default 365)", required: false },
|
|
65975
|
+
all: { type: "boolean", description: "Every order the store has", required: false, default: false },
|
|
65976
|
+
country: { type: "string", description: "Only orders to this country (two-letter code, like DE)", required: false }
|
|
65977
|
+
};
|
|
65978
|
+
function split(answer) {
|
|
65979
|
+
const { store, window: window2, history, basis, ...data } = answer;
|
|
65980
|
+
return { data, meta: { store, window: window2, history, basis } };
|
|
65981
|
+
}
|
|
65982
|
+
registerSchema({
|
|
65983
|
+
command: "shopify.buyers",
|
|
65984
|
+
description: `Start here for 'who buys from us', 'how many come back' and 'which campaign brings the best customers': the store's buyers in the period \u2014 how many, how many were new, repeat rate, days to a second order, guest orders \u2014 their segments (best, loyal, at risk, new, one-time, by this store's own rhythm) and the top buyers as numbered customers with their country, lifetime spend and the channel of their first order. --by campaign|channel adds lifetime value per acquisition campaign or channel (Baker keeps no ad spend: read it with the ads commands for the same dates). ${PERIOD_NOTE} A buyer is a Shopify customer: guest orders count in money, never as buyers.`,
|
|
65985
|
+
args: {
|
|
65986
|
+
...periodArgs,
|
|
65987
|
+
segment: {
|
|
65988
|
+
type: "string",
|
|
65989
|
+
description: "Only one segment's buyers: best | loyal | at_risk | new | one_time",
|
|
65990
|
+
required: false,
|
|
65991
|
+
enum: ["best", "loyal", "at_risk", "new", "one_time"]
|
|
65992
|
+
},
|
|
65993
|
+
by: {
|
|
65994
|
+
type: "string",
|
|
65995
|
+
description: "Lifetime value by the campaign or channel of each buyer's first order",
|
|
65996
|
+
required: false,
|
|
65997
|
+
enum: ["campaign", "channel"]
|
|
65998
|
+
},
|
|
65999
|
+
channel: {
|
|
66000
|
+
type: "string",
|
|
66001
|
+
description: "Only buyers who first came through this channel (a key from --by channel)",
|
|
66002
|
+
required: false
|
|
66003
|
+
},
|
|
66004
|
+
sort: {
|
|
66005
|
+
type: "string",
|
|
66006
|
+
description: "net (lifetime spend, default) | orders | recent (last order) | first (first order)",
|
|
66007
|
+
required: false,
|
|
66008
|
+
enum: ["net", "orders", "recent", "first"]
|
|
66009
|
+
},
|
|
66010
|
+
limit: { type: "number", description: "Buyers listed, 1-100 (default 10)", required: false },
|
|
66011
|
+
offset: { type: "number", description: "Skip this many buyers (paging)", required: false },
|
|
66012
|
+
full: {
|
|
66013
|
+
...fullArg,
|
|
66014
|
+
description: "Add each buyer's gross, refunds, orders with a discount, days between orders and first-order campaign"
|
|
65177
66015
|
}
|
|
65178
|
-
|
|
65179
|
-
|
|
65180
|
-
|
|
66016
|
+
}
|
|
66017
|
+
});
|
|
66018
|
+
var buyersCommand = defineCommand209({
|
|
66019
|
+
meta: {
|
|
66020
|
+
name: "buyers",
|
|
66021
|
+
description: "Who buys: buyers, new and returning, repeat rate, segments and the top buyers. Start here: baker shopify buyers --days 90 --by channel"
|
|
66022
|
+
},
|
|
66023
|
+
args: {
|
|
66024
|
+
...periodFlags,
|
|
66025
|
+
segment: { type: "string", description: "best | loyal | at_risk | new | one_time", required: false },
|
|
66026
|
+
by: { type: "string", description: "campaign | channel", required: false },
|
|
66027
|
+
channel: { type: "string", description: "A channel key from --by channel", required: false },
|
|
66028
|
+
sort: { type: "string", description: "net | orders | recent | first", required: false },
|
|
66029
|
+
limit: { type: "string", description: "Buyers listed, 1-100", required: false },
|
|
66030
|
+
offset: { type: "string", description: "Skip this many buyers", required: false },
|
|
66031
|
+
full: { type: "boolean", description: "Add each buyer's detail", required: false, default: false }
|
|
66032
|
+
},
|
|
66033
|
+
run: async ({ args: args5 }) => {
|
|
66034
|
+
try {
|
|
66035
|
+
const answer = await apiGet(
|
|
66036
|
+
"/api/shopify/buyers",
|
|
66037
|
+
params({
|
|
66038
|
+
days: args5.days,
|
|
66039
|
+
all: args5.all,
|
|
66040
|
+
country: args5.country,
|
|
66041
|
+
segment: args5.segment,
|
|
66042
|
+
by: args5.by,
|
|
66043
|
+
channel: args5.channel,
|
|
66044
|
+
sort: args5.sort,
|
|
66045
|
+
limit: args5.limit,
|
|
66046
|
+
offset: args5.offset,
|
|
66047
|
+
full: args5.full
|
|
66048
|
+
})
|
|
66049
|
+
);
|
|
66050
|
+
const { data, meta } = split(answer);
|
|
66051
|
+
emit2(data, meta, [...storeStateHints(answer.store), ...buyersHints(answer)]);
|
|
66052
|
+
} catch (err) {
|
|
66053
|
+
fail9(err);
|
|
65181
66054
|
}
|
|
65182
66055
|
}
|
|
65183
|
-
|
|
65184
|
-
|
|
65185
|
-
|
|
65186
|
-
|
|
65187
|
-
|
|
65188
|
-
|
|
65189
|
-
|
|
65190
|
-
for (const [name, value] of Object.entries(entries)) {
|
|
65191
|
-
if (value === void 0 || value === "" || value === false) continue;
|
|
65192
|
-
out[name] = String(value);
|
|
66056
|
+
});
|
|
66057
|
+
registerSchema({
|
|
66058
|
+
command: "shopify.buyer",
|
|
66059
|
+
description: "One buyer by their number (1042, #1042 or 'Customer #1042'): where they are, how many orders and how much they spent net of refunds, average order, days between orders, first and last order, discount use, segment and how they first came \u2014 then every order (date in the store's time, products and quantities, net, refunded, discount codes, city), newest first, and what they bought. Never a name or an email. A buyer their store asked Baker to erase, or merged into another, answers 'This buyer is no longer in Baker'.",
|
|
66060
|
+
args: {
|
|
66061
|
+
number: { type: "positional", description: "The buyer's number: 1042, #1042 or 'Customer #1042'", required: true },
|
|
66062
|
+
full: { ...fullArg, description: "Add each order's id, lines with their amounts, refunded lines and campaign" }
|
|
65193
66063
|
}
|
|
65194
|
-
|
|
65195
|
-
|
|
65196
|
-
|
|
65197
|
-
|
|
65198
|
-
|
|
65199
|
-
|
|
65200
|
-
|
|
65201
|
-
}
|
|
66064
|
+
});
|
|
66065
|
+
var buyerCommand = defineCommand209({
|
|
66066
|
+
meta: {
|
|
66067
|
+
name: "buyer",
|
|
66068
|
+
description: "One buyer's history by number. Example: baker shopify buyer 1042"
|
|
66069
|
+
},
|
|
66070
|
+
args: {
|
|
66071
|
+
number: { type: "positional", description: "1042, #1042 or 'Customer #1042'", required: true },
|
|
66072
|
+
full: { type: "boolean", description: "Add ids, lines and campaigns", required: false, default: false }
|
|
66073
|
+
},
|
|
66074
|
+
run: async ({ args: args5 }) => {
|
|
66075
|
+
try {
|
|
66076
|
+
const answer = await apiGet(
|
|
66077
|
+
"/api/shopify/buyer",
|
|
66078
|
+
params({ number: args5.number, full: args5.full })
|
|
66079
|
+
);
|
|
66080
|
+
const { data, meta } = split(answer);
|
|
66081
|
+
emit2(data, meta, [...storeStateHints(answer.store), ...buyerHistoryHints(answer.history, answer.basis)]);
|
|
66082
|
+
} catch (err) {
|
|
66083
|
+
fail9(err);
|
|
66084
|
+
}
|
|
66085
|
+
}
|
|
66086
|
+
});
|
|
66087
|
+
registerSchema({
|
|
66088
|
+
command: "shopify.countries",
|
|
66089
|
+
description: `Start here for 'where do our buyers come from' and 'which countries should we push': orders, buyers, new buyers, net, average order, share and growth against the period before, by country \u2014 or by region inside --country, or by city inside --country and --region \u2014 with the currency buyers paid in. Orders whose address Baker could not read are 'Unknown', always shown; the rows, Unknown and 'Other' add up to the total. --product narrows to the orders holding one product, with that product's money. ${PERIOD_NOTE}`,
|
|
66090
|
+
args: {
|
|
66091
|
+
...periodArgs,
|
|
66092
|
+
region: { type: "string", description: "Inside --country, one region (code or name): its cities", required: false },
|
|
66093
|
+
product: { type: "string", description: "Only orders holding this product: its id or handle", required: false },
|
|
66094
|
+
limit: { type: "number", description: "Places listed, 1-100 (default 25; the rest are 'Other')", required: false },
|
|
66095
|
+
full: { ...fullArg, description: "Add the period before's net and orders per place" }
|
|
66096
|
+
}
|
|
66097
|
+
});
|
|
66098
|
+
var countriesCommand2 = defineCommand209({
|
|
66099
|
+
meta: {
|
|
66100
|
+
name: "countries",
|
|
66101
|
+
description: "Where buyers are: orders, buyers and net by country, region or city, with growth. Start here: baker shopify countries --days 90"
|
|
66102
|
+
},
|
|
66103
|
+
args: {
|
|
66104
|
+
...periodFlags,
|
|
66105
|
+
region: { type: "string", description: "A region inside --country", required: false },
|
|
66106
|
+
product: { type: "string", description: "A product's id or handle", required: false },
|
|
66107
|
+
limit: { type: "string", description: "Places listed, 1-100", required: false },
|
|
66108
|
+
full: { type: "boolean", description: "Add the period before", required: false, default: false }
|
|
66109
|
+
},
|
|
66110
|
+
run: async ({ args: args5 }) => {
|
|
66111
|
+
try {
|
|
66112
|
+
const answer = await apiGet(
|
|
66113
|
+
"/api/shopify/countries",
|
|
66114
|
+
params({
|
|
66115
|
+
days: args5.days,
|
|
66116
|
+
all: args5.all,
|
|
66117
|
+
country: args5.country,
|
|
66118
|
+
region: args5.region,
|
|
66119
|
+
product: args5.product,
|
|
66120
|
+
limit: args5.limit,
|
|
66121
|
+
full: args5.full
|
|
66122
|
+
})
|
|
66123
|
+
);
|
|
66124
|
+
const { data, meta } = split(answer);
|
|
66125
|
+
emit2(data, meta, [...storeStateHints(answer.store), ...countriesHints(answer)]);
|
|
66126
|
+
} catch (err) {
|
|
66127
|
+
fail9(err);
|
|
66128
|
+
}
|
|
66129
|
+
}
|
|
66130
|
+
});
|
|
66131
|
+
registerSchema({
|
|
66132
|
+
command: "shopify.bestSellers",
|
|
66133
|
+
description: `Start here for 'what sells best' and 'which product should we lead with': best sellers by units ordered (before anything came back) beside refunded units, orders, buyers, revenue (the lines' price after discounts, before tax and shipping), refunds, refund rate and growth. --view variants (one product's options, with --product), trend (top products by month), together (products bought in one order), repeat (first buys whose buyers came back most) or momentum (products selling 30% or more below the period before). ${PERIOD_NOTE} For the catalog itself use \`baker shopify products\`.`,
|
|
66134
|
+
args: {
|
|
66135
|
+
...periodArgs,
|
|
66136
|
+
view: {
|
|
66137
|
+
type: "string",
|
|
66138
|
+
description: "products (default) | variants | trend | together | repeat | momentum",
|
|
66139
|
+
required: false,
|
|
66140
|
+
enum: ["products", "variants", "trend", "together", "repeat", "momentum"]
|
|
66141
|
+
},
|
|
66142
|
+
sort: {
|
|
66143
|
+
type: "string",
|
|
66144
|
+
description: "units (default) | revenue | orders",
|
|
66145
|
+
required: false,
|
|
66146
|
+
enum: ["units", "revenue", "orders"]
|
|
66147
|
+
},
|
|
66148
|
+
product: { type: "string", description: "One product (id or handle): its variants or its trend", required: false },
|
|
66149
|
+
limit: { type: "number", description: "Rows, 1-100 (default 10; 5 products for trend)", required: false },
|
|
66150
|
+
full: { ...fullArg, description: "Add product and variant ids and the period before" }
|
|
66151
|
+
}
|
|
66152
|
+
});
|
|
66153
|
+
var bestSellersCommand = defineCommand209({
|
|
66154
|
+
meta: {
|
|
66155
|
+
name: "best-sellers",
|
|
66156
|
+
description: "What sells: best sellers, variants, trend, bought together, repeat leaders, losing momentum. Start here: baker shopify best-sellers --days 90"
|
|
66157
|
+
},
|
|
66158
|
+
args: {
|
|
66159
|
+
...periodFlags,
|
|
66160
|
+
view: {
|
|
66161
|
+
type: "string",
|
|
66162
|
+
description: "products | variants | trend | together | repeat | momentum",
|
|
66163
|
+
required: false
|
|
66164
|
+
},
|
|
66165
|
+
sort: { type: "string", description: "units | revenue | orders", required: false },
|
|
66166
|
+
product: { type: "string", description: "A product's id or handle", required: false },
|
|
66167
|
+
limit: { type: "string", description: "Rows, 1-100", required: false },
|
|
66168
|
+
full: { type: "boolean", description: "Add ids and the period before", required: false, default: false }
|
|
66169
|
+
},
|
|
66170
|
+
run: async ({ args: args5 }) => {
|
|
66171
|
+
try {
|
|
66172
|
+
const answer = await apiGet(
|
|
66173
|
+
"/api/shopify/best-sellers",
|
|
66174
|
+
params({
|
|
66175
|
+
days: args5.days,
|
|
66176
|
+
all: args5.all,
|
|
66177
|
+
country: args5.country,
|
|
66178
|
+
view: args5.view,
|
|
66179
|
+
sort: args5.sort,
|
|
66180
|
+
product: args5.product,
|
|
66181
|
+
limit: args5.limit,
|
|
66182
|
+
full: args5.full
|
|
66183
|
+
})
|
|
66184
|
+
);
|
|
66185
|
+
const { data, meta } = split(answer);
|
|
66186
|
+
emit2(data, meta, [...storeStateHints(answer.store), ...bestSellersHints(answer)]);
|
|
66187
|
+
} catch (err) {
|
|
66188
|
+
fail9(err);
|
|
66189
|
+
}
|
|
66190
|
+
}
|
|
66191
|
+
});
|
|
66192
|
+
registerSchema({
|
|
66193
|
+
command: "shopify.cohorts",
|
|
66194
|
+
description: "Buyers grouped by the month of their first order (the last --months, default 12): how many, the share who ordered again 1, 2, 3, 6 and 12 months later, and what they spent per buyer by month 12. Months not reached yet are null. Use it for 'are buyers coming back more than they used to' and lifetime value over time.",
|
|
66195
|
+
args: {
|
|
66196
|
+
months: { type: "number", description: "Cohorts, the last 3-36 months (default 12)", required: false },
|
|
66197
|
+
country: { type: "string", description: "Only orders to this country (two-letter code)", required: false },
|
|
66198
|
+
full: {
|
|
66199
|
+
...fullArg,
|
|
66200
|
+
description: "Add every month of every cohort: active buyers, orders, net, cumulative net per buyer"
|
|
66201
|
+
}
|
|
66202
|
+
}
|
|
66203
|
+
});
|
|
66204
|
+
var cohortsCommand = defineCommand209({
|
|
66205
|
+
meta: {
|
|
66206
|
+
name: "cohorts",
|
|
66207
|
+
description: "Buyers by first-order month: who came back and what they spent. Example: baker shopify cohorts --months 12"
|
|
66208
|
+
},
|
|
66209
|
+
args: {
|
|
66210
|
+
months: { type: "string", description: "The last 3-36 months", required: false },
|
|
66211
|
+
country: { type: "string", description: "A two-letter country code", required: false },
|
|
66212
|
+
full: { type: "boolean", description: "Every month of every cohort", required: false, default: false }
|
|
66213
|
+
},
|
|
66214
|
+
run: async ({ args: args5 }) => {
|
|
66215
|
+
try {
|
|
66216
|
+
const answer = await apiGet(
|
|
66217
|
+
"/api/shopify/cohorts",
|
|
66218
|
+
params({ months: args5.months, country: args5.country, full: args5.full })
|
|
66219
|
+
);
|
|
66220
|
+
const { data, meta } = split(answer);
|
|
66221
|
+
emit2(data, meta, [...storeStateHints(answer.store), ...cohortsHints(answer)]);
|
|
66222
|
+
} catch (err) {
|
|
66223
|
+
fail9(err);
|
|
66224
|
+
}
|
|
66225
|
+
}
|
|
66226
|
+
});
|
|
66227
|
+
registerSchema({
|
|
66228
|
+
command: "shopify.segments",
|
|
66229
|
+
description: "Every buyer at the period's end by segment \u2014 best buyers, loyal, at risk, new and one-time \u2014 with how many, their share, net, average orders, days since their last order, the countries they are in and the products their first orders held. Each segment's rule is given in words with this store's own numbers (its typical gap between orders and the spend of its top fifth). Start here for 'who are our best customers' and 'who should we win back'.",
|
|
66230
|
+
args: {
|
|
66231
|
+
...periodArgs,
|
|
66232
|
+
full: { ...fullArg, description: "Add the first products' ids" }
|
|
66233
|
+
}
|
|
66234
|
+
});
|
|
66235
|
+
var segmentsCommand = defineCommand209({
|
|
66236
|
+
meta: {
|
|
66237
|
+
name: "segments",
|
|
66238
|
+
description: "Buyers by segment: best, loyal, at risk, new, one-time. Example: baker shopify segments"
|
|
66239
|
+
},
|
|
66240
|
+
args: {
|
|
66241
|
+
...periodFlags,
|
|
66242
|
+
full: { type: "boolean", description: "Add product ids", required: false, default: false }
|
|
66243
|
+
},
|
|
66244
|
+
run: async ({ args: args5 }) => {
|
|
66245
|
+
try {
|
|
66246
|
+
const answer = await apiGet(
|
|
66247
|
+
"/api/shopify/segments",
|
|
66248
|
+
params({ days: args5.days, all: args5.all, country: args5.country, full: args5.full })
|
|
66249
|
+
);
|
|
66250
|
+
const { data, meta } = split(answer);
|
|
66251
|
+
emit2(data, meta, [...storeStateHints(answer.store), ...segmentsHints(answer)]);
|
|
66252
|
+
} catch (err) {
|
|
66253
|
+
fail9(err);
|
|
66254
|
+
}
|
|
66255
|
+
}
|
|
66256
|
+
});
|
|
66257
|
+
|
|
66258
|
+
// src/commands/shopify/index.ts
|
|
65202
66259
|
registerSchema({
|
|
65203
66260
|
command: "shopify.store",
|
|
65204
66261
|
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.',
|
|
@@ -65294,7 +66351,77 @@ registerSchema({
|
|
|
65294
66351
|
full: { ...fullArg, description: "Add each option's SKU and each product's Baker link" }
|
|
65295
66352
|
}
|
|
65296
66353
|
});
|
|
65297
|
-
|
|
66354
|
+
registerSchema({
|
|
66355
|
+
command: "shopify.sales",
|
|
66356
|
+
description: "Start here for 'how much did we sell', 'which campaigns or pages brought sales' and 'which products sold most': the connected store's orders, sales, refunds and net, in the store's currency. --by day (default) and --by product count each sale, addition and refund in the period it happened; --by campaign and --by landing take the orders paid in the period and credit each to the campaign or Baker page that brought its buyer, with what was added to and refunded on it since \u2014 so the rows add up to `totals` exactly, with named rows for sales from before Baker measured the store and sales from no campaign. A sale counts when it is paid, at what was received. `salesReporting` says who reports the sales to Meta and Google: `undecided` and `shopify_channel` mean Baker only reports them, and only a manager can change that in Brain \u2192 Store. --by weekday|hour|month|month_of_year says when buyers order, in the store's own time, from the store's whole order history (orders placed in the period, with what was refunded on them since): use it for when to run or schedule campaigns; only these take --days up to 3650 or --all.",
|
|
66357
|
+
args: {
|
|
66358
|
+
days: {
|
|
66359
|
+
type: "number",
|
|
66360
|
+
description: "The last N days: 1-395 by day, product, campaign or landing; 1-3650 by weekday, hour or month (default 30)",
|
|
66361
|
+
required: false
|
|
66362
|
+
},
|
|
66363
|
+
all: {
|
|
66364
|
+
type: "boolean",
|
|
66365
|
+
description: "Every order the store has (by weekday, hour, month or month_of_year only)",
|
|
66366
|
+
required: false,
|
|
66367
|
+
default: false
|
|
66368
|
+
},
|
|
66369
|
+
by: {
|
|
66370
|
+
type: "string",
|
|
66371
|
+
description: "day | product | campaign | landing | weekday | hour | month | month_of_year (default day)",
|
|
66372
|
+
required: false,
|
|
66373
|
+
enum: ["day", "product", "campaign", "landing", "weekday", "hour", "month", "month_of_year"]
|
|
66374
|
+
},
|
|
66375
|
+
limit: {
|
|
66376
|
+
type: "number",
|
|
66377
|
+
description: "Rows of a breakdown, 1-100 (by campaign or landing the rest are folded into one 'other' row)",
|
|
66378
|
+
required: false
|
|
66379
|
+
},
|
|
66380
|
+
full: {
|
|
66381
|
+
...fullArg,
|
|
66382
|
+
description: "Add each row's source, medium, campaign, click platform, landing id or product id"
|
|
66383
|
+
}
|
|
66384
|
+
}
|
|
66385
|
+
});
|
|
66386
|
+
var salesCommand = defineCommand210({
|
|
66387
|
+
meta: {
|
|
66388
|
+
name: "sales",
|
|
66389
|
+
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"
|
|
66390
|
+
},
|
|
66391
|
+
args: {
|
|
66392
|
+
days: {
|
|
66393
|
+
type: "string",
|
|
66394
|
+
description: "The last N days (1-395; up to 3650 by weekday, hour or month)",
|
|
66395
|
+
required: false
|
|
66396
|
+
},
|
|
66397
|
+
all: {
|
|
66398
|
+
type: "boolean",
|
|
66399
|
+
description: "Every order (by weekday, hour or month only)",
|
|
66400
|
+
required: false,
|
|
66401
|
+
default: false
|
|
66402
|
+
},
|
|
66403
|
+
by: {
|
|
66404
|
+
type: "string",
|
|
66405
|
+
description: "day | product | campaign | landing | weekday | hour | month | month_of_year (default day)",
|
|
66406
|
+
required: false
|
|
66407
|
+
},
|
|
66408
|
+
limit: { type: "string", description: "Rows of a breakdown, 1-100", required: false },
|
|
66409
|
+
full: { type: "boolean", description: "Add sources, campaigns and ids per row", required: false, default: false }
|
|
66410
|
+
},
|
|
66411
|
+
run: async ({ args: args5 }) => {
|
|
66412
|
+
try {
|
|
66413
|
+
const answer = await apiGet(
|
|
66414
|
+
"/api/shopify/sales",
|
|
66415
|
+
params({ days: args5.days, all: args5.all, by: args5.by, limit: args5.limit, full: args5.full })
|
|
66416
|
+
);
|
|
66417
|
+
const { store, salesReporting, history, ...data } = answer;
|
|
66418
|
+
emit2(data, { store, salesReporting, history }, [...storeStateHints(store), ...salesHints(answer)]);
|
|
66419
|
+
} catch (err) {
|
|
66420
|
+
fail9(err);
|
|
66421
|
+
}
|
|
66422
|
+
}
|
|
66423
|
+
});
|
|
66424
|
+
var storeCommand = defineCommand210({
|
|
65298
66425
|
meta: {
|
|
65299
66426
|
name: "store",
|
|
65300
66427
|
description: "The connected Shopify store: currency, countries, how many products, what is out of stock. Example: baker shopify store"
|
|
@@ -65311,7 +66438,7 @@ var storeCommand = defineCommand209({
|
|
|
65311
66438
|
}
|
|
65312
66439
|
}
|
|
65313
66440
|
});
|
|
65314
|
-
var productsCommand =
|
|
66441
|
+
var productsCommand = defineCommand210({
|
|
65315
66442
|
meta: {
|
|
65316
66443
|
name: "products",
|
|
65317
66444
|
description: 'What the store sells, with price and stock. Example: baker shopify products --search "snowboard" --stock out_of_stock'
|
|
@@ -65357,7 +66484,7 @@ var productsCommand = defineCommand209({
|
|
|
65357
66484
|
}
|
|
65358
66485
|
}
|
|
65359
66486
|
});
|
|
65360
|
-
var productCommand =
|
|
66487
|
+
var productCommand = defineCommand210({
|
|
65361
66488
|
meta: {
|
|
65362
66489
|
name: "product",
|
|
65363
66490
|
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"
|
|
@@ -65420,7 +66547,7 @@ var productCommand = defineCommand209({
|
|
|
65420
66547
|
}
|
|
65421
66548
|
}
|
|
65422
66549
|
});
|
|
65423
|
-
var collectionsCommand =
|
|
66550
|
+
var collectionsCommand = defineCommand210({
|
|
65424
66551
|
meta: {
|
|
65425
66552
|
name: "collections",
|
|
65426
66553
|
description: "The store's collections, with the handles --collection takes. Example: baker shopify collections --full"
|
|
@@ -65445,7 +66572,7 @@ var collectionsCommand = defineCommand209({
|
|
|
65445
66572
|
}
|
|
65446
66573
|
}
|
|
65447
66574
|
});
|
|
65448
|
-
var stockCommand2 =
|
|
66575
|
+
var stockCommand2 = defineCommand210({
|
|
65449
66576
|
meta: {
|
|
65450
66577
|
name: "stock",
|
|
65451
66578
|
description: "Every product with options out of stock, naming them. Example: baker shopify stock"
|
|
@@ -65462,18 +66589,18 @@ var stockCommand2 = defineCommand209({
|
|
|
65462
66589
|
params({ collection: args5.collection, limit: args5.limit, full: args5.full })
|
|
65463
66590
|
);
|
|
65464
66591
|
const { store, ...data } = answer;
|
|
65465
|
-
const
|
|
65466
|
-
emit2(data, { store }, [...storeStateHints(store), ...stockHints(answer, Number.isFinite(
|
|
66592
|
+
const limit2 = Number(args5.limit ?? 50);
|
|
66593
|
+
emit2(data, { store }, [...storeStateHints(store), ...stockHints(answer, Number.isFinite(limit2) ? limit2 : 50)]);
|
|
65467
66594
|
} catch (err) {
|
|
65468
66595
|
fail9(err);
|
|
65469
66596
|
}
|
|
65470
66597
|
}
|
|
65471
66598
|
});
|
|
65472
|
-
var shopifyCommand =
|
|
66599
|
+
var shopifyCommand = defineCommand210({
|
|
65473
66600
|
meta: {
|
|
65474
66601
|
name: "shopify",
|
|
65475
|
-
description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections
|
|
65476
|
-
and
|
|
66602
|
+
description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections,
|
|
66603
|
+
product photos, what it sold, and who buys, where and what. Read-only: nothing here changes the store.
|
|
65477
66604
|
|
|
65478
66605
|
Examples:
|
|
65479
66606
|
baker shopify store # currency, countries, how many products, what is out of stock
|
|
@@ -65487,6 +66614,14 @@ Examples:
|
|
|
65487
66614
|
baker shopify product <id> --out-of-stock # only its options that are out of stock
|
|
65488
66615
|
baker shopify stock # every product with options out of stock
|
|
65489
66616
|
baker shopify collections # collections, with handles for --collection
|
|
66617
|
+
baker shopify sales --days 7 --by campaign # what sold and which campaigns brought it (--by day|product|landing)
|
|
66618
|
+
baker shopify sales --all --by weekday # when buyers order, in the store's time (--by hour|month|month_of_year)
|
|
66619
|
+
baker shopify countries --days 90 # where buyers are, with growth (--country DE for its regions)
|
|
66620
|
+
baker shopify best-sellers --days 90 # what sells (--view variants|trend|together|repeat|momentum)
|
|
66621
|
+
baker shopify buyers --days 90 --by channel # who buys, repeat rate, segments, value by acquisition channel
|
|
66622
|
+
baker shopify buyer 1042 # one numbered customer's orders
|
|
66623
|
+
baker shopify segments # best, loyal, at risk, new, one-time \u2014 and who to find more of
|
|
66624
|
+
baker shopify cohorts --months 12 # buyers by first-order month: who came back
|
|
65490
66625
|
|
|
65491
66626
|
Product photos are already in the image library: place them by imageId
|
|
65492
66627
|
(baker images download <imageIds> --out src/pages/<page>/_images/), never by a cdn.shopify.com link.
|
|
@@ -65502,15 +66637,22 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
|
65502
66637
|
products: productsCommand,
|
|
65503
66638
|
product: productCommand,
|
|
65504
66639
|
collections: collectionsCommand,
|
|
65505
|
-
stock: stockCommand2
|
|
66640
|
+
stock: stockCommand2,
|
|
66641
|
+
sales: salesCommand,
|
|
66642
|
+
buyers: buyersCommand,
|
|
66643
|
+
buyer: buyerCommand,
|
|
66644
|
+
countries: countriesCommand2,
|
|
66645
|
+
"best-sellers": bestSellersCommand,
|
|
66646
|
+
cohorts: cohortsCommand,
|
|
66647
|
+
segments: segmentsCommand
|
|
65506
66648
|
}
|
|
65507
66649
|
});
|
|
65508
66650
|
|
|
65509
66651
|
// src/commands/studio/index.ts
|
|
65510
|
-
import { defineCommand as
|
|
66652
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
65511
66653
|
|
|
65512
66654
|
// src/commands/studio/animate.ts
|
|
65513
|
-
import { defineCommand as
|
|
66655
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
65514
66656
|
|
|
65515
66657
|
// src/commands/studio/spokenPace.ts
|
|
65516
66658
|
var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
|
|
@@ -65521,9 +66663,9 @@ function wordsThatFit(seconds) {
|
|
|
65521
66663
|
function spokenPaceHint(prompt, seconds, model) {
|
|
65522
66664
|
const words2 = spokenWords(prompt);
|
|
65523
66665
|
if (words2 === 0) return null;
|
|
65524
|
-
const
|
|
65525
|
-
if (
|
|
65526
|
-
return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${
|
|
66666
|
+
const split2 = model ? splitScriptFor(words2, model) : null;
|
|
66667
|
+
if (split2) {
|
|
66668
|
+
return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${split2.maxSeconds}s (~${Math.floor(split2.maxSeconds * WORDS_PER_SECOND3)} words). It will not refuse and it will not cut: it will RUSH, swallowing syllables. Split the script into ${split2.clips} takes of roughly ${split2.wordsPerClip} words each, rendered separately and cut together \u2014 break it where the thought breaks, not mid-sentence. Or move to a model that renders longer (bytedance/seedance-2.5 goes to 30s).`;
|
|
65527
66669
|
}
|
|
65528
66670
|
if (!seconds) return null;
|
|
65529
66671
|
const fits = wordsThatFit(seconds);
|
|
@@ -65738,10 +66880,10 @@ var defaultDeps = {
|
|
|
65738
66880
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
65739
66881
|
upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
|
|
65740
66882
|
};
|
|
65741
|
-
async function resolveLibraryImageIds(spec,
|
|
66883
|
+
async function resolveLibraryImageIds(spec, limit2, deps = defaultDeps) {
|
|
65742
66884
|
const refs = parseImageRefs(spec);
|
|
65743
|
-
if (
|
|
65744
|
-
throw new ApiError("VALIDATION_ERROR",
|
|
66885
|
+
if (limit2 && refs.length > limit2.max) {
|
|
66886
|
+
throw new ApiError("VALIDATION_ERROR", limit2.refuse(refs.length));
|
|
65745
66887
|
}
|
|
65746
66888
|
const imageIds = [];
|
|
65747
66889
|
const added = [];
|
|
@@ -66023,7 +67165,7 @@ async function adByHandHintFor(body) {
|
|
|
66023
67165
|
return null;
|
|
66024
67166
|
}
|
|
66025
67167
|
}
|
|
66026
|
-
var animateCommand =
|
|
67168
|
+
var animateCommand = defineCommand211({
|
|
66027
67169
|
meta: {
|
|
66028
67170
|
name: "animate",
|
|
66029
67171
|
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"
|
|
@@ -66148,7 +67290,7 @@ var animateCommand = defineCommand210({
|
|
|
66148
67290
|
});
|
|
66149
67291
|
|
|
66150
67292
|
// src/commands/studio/generate.ts
|
|
66151
|
-
import { defineCommand as
|
|
67293
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
66152
67294
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
66153
67295
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
66154
67296
|
registerSchema({
|
|
@@ -66236,11 +67378,11 @@ registerSchema({
|
|
|
66236
67378
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
66237
67379
|
}
|
|
66238
67380
|
});
|
|
66239
|
-
function parseJsonArg(raw,
|
|
67381
|
+
function parseJsonArg(raw, flag3) {
|
|
66240
67382
|
try {
|
|
66241
67383
|
return JSON.parse(raw);
|
|
66242
67384
|
} catch {
|
|
66243
|
-
throw new ApiError("VALIDATION_ERROR", `--${
|
|
67385
|
+
throw new ApiError("VALIDATION_ERROR", `--${flag3} must be valid JSON (got: ${raw})`);
|
|
66244
67386
|
}
|
|
66245
67387
|
}
|
|
66246
67388
|
function referenceLimitFor(model) {
|
|
@@ -66284,7 +67426,7 @@ function buildGenerateBody(args5, prompt) {
|
|
|
66284
67426
|
}
|
|
66285
67427
|
return body;
|
|
66286
67428
|
}
|
|
66287
|
-
var generateCommand =
|
|
67429
|
+
var generateCommand = defineCommand212({
|
|
66288
67430
|
meta: {
|
|
66289
67431
|
name: "generate",
|
|
66290
67432
|
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]]'"
|
|
@@ -66367,7 +67509,7 @@ var generateCommand = defineCommand211({
|
|
|
66367
67509
|
});
|
|
66368
67510
|
|
|
66369
67511
|
// src/commands/studio/get.ts
|
|
66370
|
-
import { defineCommand as
|
|
67512
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
66371
67513
|
registerSchema({
|
|
66372
67514
|
command: "studio.get",
|
|
66373
67515
|
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.",
|
|
@@ -66376,7 +67518,7 @@ registerSchema({
|
|
|
66376
67518
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
66377
67519
|
}
|
|
66378
67520
|
});
|
|
66379
|
-
var getCommand5 =
|
|
67521
|
+
var getCommand5 = defineCommand213({
|
|
66380
67522
|
meta: {
|
|
66381
67523
|
name: "get",
|
|
66382
67524
|
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"
|
|
@@ -66405,7 +67547,7 @@ var getCommand5 = defineCommand212({
|
|
|
66405
67547
|
});
|
|
66406
67548
|
|
|
66407
67549
|
// src/commands/studio/improve.ts
|
|
66408
|
-
import { defineCommand as
|
|
67550
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
66409
67551
|
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.";
|
|
66410
67552
|
registerSchema({
|
|
66411
67553
|
command: "studio.improve",
|
|
@@ -66430,7 +67572,7 @@ registerSchema({
|
|
|
66430
67572
|
}
|
|
66431
67573
|
}
|
|
66432
67574
|
});
|
|
66433
|
-
var improveCommand =
|
|
67575
|
+
var improveCommand = defineCommand214({
|
|
66434
67576
|
meta: {
|
|
66435
67577
|
name: "improve",
|
|
66436
67578
|
description: `${DESCRIPTION2}
|
|
@@ -66474,7 +67616,7 @@ Examples:
|
|
|
66474
67616
|
});
|
|
66475
67617
|
|
|
66476
67618
|
// src/commands/studio/keep.ts
|
|
66477
|
-
import { defineCommand as
|
|
67619
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
66478
67620
|
registerSchema({
|
|
66479
67621
|
command: "studio.keep",
|
|
66480
67622
|
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.",
|
|
@@ -66484,7 +67626,7 @@ registerSchema({
|
|
|
66484
67626
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
66485
67627
|
}
|
|
66486
67628
|
});
|
|
66487
|
-
var keepCommand =
|
|
67629
|
+
var keepCommand = defineCommand215({
|
|
66488
67630
|
meta: {
|
|
66489
67631
|
name: "keep",
|
|
66490
67632
|
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"
|
|
@@ -66535,7 +67677,7 @@ var keepCommand = defineCommand214({
|
|
|
66535
67677
|
});
|
|
66536
67678
|
|
|
66537
67679
|
// src/commands/studio/list.ts
|
|
66538
|
-
import { defineCommand as
|
|
67680
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
66539
67681
|
registerSchema({
|
|
66540
67682
|
command: "studio.list",
|
|
66541
67683
|
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.",
|
|
@@ -66546,7 +67688,7 @@ registerSchema({
|
|
|
66546
67688
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
66547
67689
|
}
|
|
66548
67690
|
});
|
|
66549
|
-
var listCommand18 =
|
|
67691
|
+
var listCommand18 = defineCommand216({
|
|
66550
67692
|
meta: {
|
|
66551
67693
|
name: "list",
|
|
66552
67694
|
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"
|
|
@@ -66580,7 +67722,7 @@ var listCommand18 = defineCommand215({
|
|
|
66580
67722
|
});
|
|
66581
67723
|
|
|
66582
67724
|
// src/commands/studio/models.ts
|
|
66583
|
-
import { defineCommand as
|
|
67725
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
66584
67726
|
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.";
|
|
66585
67727
|
registerSchema({
|
|
66586
67728
|
command: "studio.models",
|
|
@@ -66667,7 +67809,7 @@ function buildModelCards(kind, model) {
|
|
|
66667
67809
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
66668
67810
|
return selected.map((id) => build(id));
|
|
66669
67811
|
}
|
|
66670
|
-
var modelsCommand =
|
|
67812
|
+
var modelsCommand = defineCommand217({
|
|
66671
67813
|
meta: {
|
|
66672
67814
|
name: "models",
|
|
66673
67815
|
description: `${DESCRIPTION3}
|
|
@@ -66714,13 +67856,13 @@ Examples:
|
|
|
66714
67856
|
});
|
|
66715
67857
|
|
|
66716
67858
|
// src/commands/studio/skills.ts
|
|
66717
|
-
import { defineCommand as
|
|
67859
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
66718
67860
|
registerSchema({
|
|
66719
67861
|
command: "studio.skills",
|
|
66720
67862
|
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.",
|
|
66721
67863
|
args: {}
|
|
66722
67864
|
});
|
|
66723
|
-
var skillsCommand =
|
|
67865
|
+
var skillsCommand = defineCommand218({
|
|
66724
67866
|
meta: {
|
|
66725
67867
|
name: "skills",
|
|
66726
67868
|
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"
|
|
@@ -66744,7 +67886,7 @@ var skillsCommand = defineCommand217({
|
|
|
66744
67886
|
});
|
|
66745
67887
|
|
|
66746
67888
|
// src/commands/studio/index.ts
|
|
66747
|
-
var studioCommand =
|
|
67889
|
+
var studioCommand = defineCommand219({
|
|
66748
67890
|
meta: {
|
|
66749
67891
|
name: "studio",
|
|
66750
67892
|
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.
|
|
@@ -66787,10 +67929,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
66787
67929
|
});
|
|
66788
67930
|
|
|
66789
67931
|
// src/commands/tag-manager/index.ts
|
|
66790
|
-
import { defineCommand as
|
|
67932
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
66791
67933
|
|
|
66792
67934
|
// src/commands/tag-manager/draft.ts
|
|
66793
|
-
import { defineCommand as
|
|
67935
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
66794
67936
|
|
|
66795
67937
|
// src/commands/tag-manager/shared.ts
|
|
66796
67938
|
import { readFileSync as readFileSync20 } from "fs";
|
|
@@ -66806,21 +67948,21 @@ function requireTarget6(args5, entity) {
|
|
|
66806
67948
|
}
|
|
66807
67949
|
return target2;
|
|
66808
67950
|
}
|
|
66809
|
-
function loadJsonArg2(args5,
|
|
66810
|
-
const inline = args5[
|
|
67951
|
+
function loadJsonArg2(args5, flag3 = "json") {
|
|
67952
|
+
const inline = args5[flag3];
|
|
66811
67953
|
const file = args5.file;
|
|
66812
67954
|
const raw = typeof file === "string" && file.length > 0 ? readFileSync20(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
66813
67955
|
if (raw === void 0) {
|
|
66814
|
-
failValidation5(`pass --${
|
|
67956
|
+
failValidation5(`pass --${flag3} with inline JSON or --file with a path to a JSON file`);
|
|
66815
67957
|
}
|
|
66816
67958
|
try {
|
|
66817
67959
|
const parsed = JSON.parse(raw);
|
|
66818
67960
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
66819
|
-
failValidation5(`--${
|
|
67961
|
+
failValidation5(`--${flag3} must be a JSON object`);
|
|
66820
67962
|
}
|
|
66821
67963
|
return parsed;
|
|
66822
67964
|
} catch {
|
|
66823
|
-
return failValidation5(`--${
|
|
67965
|
+
return failValidation5(`--${flag3} is not valid JSON`);
|
|
66824
67966
|
}
|
|
66825
67967
|
}
|
|
66826
67968
|
var RETRYABLE_CODES2 = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
@@ -66913,13 +68055,13 @@ registerSchema({
|
|
|
66913
68055
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
66914
68056
|
}
|
|
66915
68057
|
});
|
|
66916
|
-
var draftCommand5 =
|
|
68058
|
+
var draftCommand5 = defineCommand220({
|
|
66917
68059
|
meta: {
|
|
66918
68060
|
name: "draft",
|
|
66919
68061
|
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."
|
|
66920
68062
|
},
|
|
66921
68063
|
subCommands: {
|
|
66922
|
-
list:
|
|
68064
|
+
list: defineCommand220({
|
|
66923
68065
|
meta: {
|
|
66924
68066
|
name: "list",
|
|
66925
68067
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -66932,7 +68074,7 @@ var draftCommand5 = defineCommand219({
|
|
|
66932
68074
|
await draftList2(args5.json === true, args5.chat);
|
|
66933
68075
|
}
|
|
66934
68076
|
}),
|
|
66935
|
-
show:
|
|
68077
|
+
show: defineCommand220({
|
|
66936
68078
|
meta: {
|
|
66937
68079
|
name: "show",
|
|
66938
68080
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -66949,7 +68091,7 @@ var draftCommand5 = defineCommand219({
|
|
|
66949
68091
|
);
|
|
66950
68092
|
}
|
|
66951
68093
|
}),
|
|
66952
|
-
amend:
|
|
68094
|
+
amend: defineCommand220({
|
|
66953
68095
|
meta: {
|
|
66954
68096
|
name: "amend",
|
|
66955
68097
|
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."
|
|
@@ -66966,7 +68108,7 @@ var draftCommand5 = defineCommand219({
|
|
|
66966
68108
|
});
|
|
66967
68109
|
}
|
|
66968
68110
|
}),
|
|
66969
|
-
remove:
|
|
68111
|
+
remove: defineCommand220({
|
|
66970
68112
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
66971
68113
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
66972
68114
|
run: async ({ args: args5 }) => {
|
|
@@ -66975,7 +68117,7 @@ var draftCommand5 = defineCommand219({
|
|
|
66975
68117
|
});
|
|
66976
68118
|
}
|
|
66977
68119
|
}),
|
|
66978
|
-
clear:
|
|
68120
|
+
clear: defineCommand220({
|
|
66979
68121
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
66980
68122
|
run: async () => {
|
|
66981
68123
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -66985,7 +68127,7 @@ var draftCommand5 = defineCommand219({
|
|
|
66985
68127
|
});
|
|
66986
68128
|
|
|
66987
68129
|
// src/commands/tag-manager/read.ts
|
|
66988
|
-
import { defineCommand as
|
|
68130
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
66989
68131
|
registerSchema({
|
|
66990
68132
|
command: "tagManager.containers",
|
|
66991
68133
|
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.",
|
|
@@ -67026,7 +68168,7 @@ function containersHints(containers) {
|
|
|
67026
68168
|
}))
|
|
67027
68169
|
});
|
|
67028
68170
|
}
|
|
67029
|
-
var containersCommand =
|
|
68171
|
+
var containersCommand = defineCommand221({
|
|
67030
68172
|
meta: {
|
|
67031
68173
|
name: "containers",
|
|
67032
68174
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -67043,7 +68185,7 @@ Start here:
|
|
|
67043
68185
|
}
|
|
67044
68186
|
}
|
|
67045
68187
|
});
|
|
67046
|
-
var readCommand =
|
|
68188
|
+
var readCommand = defineCommand221({
|
|
67047
68189
|
meta: {
|
|
67048
68190
|
name: "read",
|
|
67049
68191
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -67085,7 +68227,7 @@ Examples:
|
|
|
67085
68227
|
});
|
|
67086
68228
|
|
|
67087
68229
|
// src/commands/tag-manager/write-commands.ts
|
|
67088
|
-
import { defineCommand as
|
|
68230
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
67089
68231
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
67090
68232
|
var ENTITIES = [
|
|
67091
68233
|
{
|
|
@@ -67141,10 +68283,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
67141
68283
|
});
|
|
67142
68284
|
}
|
|
67143
68285
|
function entityCommand(entity, noun, example) {
|
|
67144
|
-
return
|
|
68286
|
+
return defineCommand222({
|
|
67145
68287
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
67146
68288
|
subCommands: {
|
|
67147
|
-
create:
|
|
68289
|
+
create: defineCommand222({
|
|
67148
68290
|
meta: {
|
|
67149
68291
|
name: "create",
|
|
67150
68292
|
description: `Stage a new ${noun}
|
|
@@ -67166,7 +68308,7 @@ Examples:
|
|
|
67166
68308
|
});
|
|
67167
68309
|
}
|
|
67168
68310
|
}),
|
|
67169
|
-
update:
|
|
68311
|
+
update: defineCommand222({
|
|
67170
68312
|
meta: {
|
|
67171
68313
|
name: "update",
|
|
67172
68314
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -67186,7 +68328,7 @@ Examples:
|
|
|
67186
68328
|
});
|
|
67187
68329
|
}
|
|
67188
68330
|
}),
|
|
67189
|
-
delete:
|
|
68331
|
+
delete: defineCommand222({
|
|
67190
68332
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
67191
68333
|
args: {
|
|
67192
68334
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -67227,7 +68369,7 @@ function builtinTypes(args5) {
|
|
|
67227
68369
|
}
|
|
67228
68370
|
return raw.split(",").map((entry) => entry.trim());
|
|
67229
68371
|
}
|
|
67230
|
-
var builtinCommand =
|
|
68372
|
+
var builtinCommand = defineCommand222({
|
|
67231
68373
|
meta: {
|
|
67232
68374
|
name: "builtin",
|
|
67233
68375
|
description: `Enable or disable built-in variables
|
|
@@ -67237,7 +68379,7 @@ Examples:
|
|
|
67237
68379
|
baker tag-manager builtin disable --types formId`
|
|
67238
68380
|
},
|
|
67239
68381
|
subCommands: {
|
|
67240
|
-
enable:
|
|
68382
|
+
enable: defineCommand222({
|
|
67241
68383
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
67242
68384
|
args: {
|
|
67243
68385
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -67251,7 +68393,7 @@ Examples:
|
|
|
67251
68393
|
});
|
|
67252
68394
|
}
|
|
67253
68395
|
}),
|
|
67254
|
-
disable:
|
|
68396
|
+
disable: defineCommand222({
|
|
67255
68397
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
67256
68398
|
args: {
|
|
67257
68399
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -67269,7 +68411,7 @@ Examples:
|
|
|
67269
68411
|
});
|
|
67270
68412
|
|
|
67271
68413
|
// src/commands/tag-manager/index.ts
|
|
67272
|
-
var tagManagerCommand =
|
|
68414
|
+
var tagManagerCommand = defineCommand223({
|
|
67273
68415
|
meta: {
|
|
67274
68416
|
name: "tag-manager",
|
|
67275
68417
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -67306,7 +68448,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
67306
68448
|
});
|
|
67307
68449
|
|
|
67308
68450
|
// src/commands/tags/index.ts
|
|
67309
|
-
import { defineCommand as
|
|
68451
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
67310
68452
|
|
|
67311
68453
|
// src/commands/tags/shared.ts
|
|
67312
68454
|
function failApi3(err) {
|
|
@@ -67386,7 +68528,7 @@ async function listTags(json) {
|
|
|
67386
68528
|
var listArgs11 = {
|
|
67387
68529
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
67388
68530
|
};
|
|
67389
|
-
var listCommand19 =
|
|
68531
|
+
var listCommand19 = defineCommand224({
|
|
67390
68532
|
meta: {
|
|
67391
68533
|
name: "list",
|
|
67392
68534
|
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"
|
|
@@ -67405,7 +68547,7 @@ async function listDraft4(chat) {
|
|
|
67405
68547
|
failApi3(err);
|
|
67406
68548
|
}
|
|
67407
68549
|
}
|
|
67408
|
-
var draftCommand6 =
|
|
68550
|
+
var draftCommand6 = defineCommand224({
|
|
67409
68551
|
meta: {
|
|
67410
68552
|
name: "draft",
|
|
67411
68553
|
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."
|
|
@@ -67415,7 +68557,7 @@ var draftCommand6 = defineCommand223({
|
|
|
67415
68557
|
await listDraft4(args5.chat);
|
|
67416
68558
|
}
|
|
67417
68559
|
});
|
|
67418
|
-
var tagsCommand4 =
|
|
68560
|
+
var tagsCommand4 = defineCommand224({
|
|
67419
68561
|
meta: {
|
|
67420
68562
|
name: "tags",
|
|
67421
68563
|
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.
|
|
@@ -67444,10 +68586,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
67444
68586
|
});
|
|
67445
68587
|
|
|
67446
68588
|
// src/commands/testimonials/index.ts
|
|
67447
|
-
import { defineCommand as
|
|
68589
|
+
import { defineCommand as defineCommand228 } from "citty";
|
|
67448
68590
|
|
|
67449
68591
|
// src/commands/testimonials/get.ts
|
|
67450
|
-
import { defineCommand as
|
|
68592
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
67451
68593
|
registerSchema({
|
|
67452
68594
|
command: "testimonials.get",
|
|
67453
68595
|
description: "Get a single testimonial by ID",
|
|
@@ -67455,7 +68597,7 @@ registerSchema({
|
|
|
67455
68597
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
67456
68598
|
}
|
|
67457
68599
|
});
|
|
67458
|
-
var getCommand6 =
|
|
68600
|
+
var getCommand6 = defineCommand225({
|
|
67459
68601
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
67460
68602
|
args: {
|
|
67461
68603
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -67492,7 +68634,7 @@ var getCommand6 = defineCommand224({
|
|
|
67492
68634
|
});
|
|
67493
68635
|
|
|
67494
68636
|
// src/commands/testimonials/list.ts
|
|
67495
|
-
import { defineCommand as
|
|
68637
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
67496
68638
|
|
|
67497
68639
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
67498
68640
|
function resolveEmptyReason({
|
|
@@ -67641,15 +68783,15 @@ var PARAM_NAMES = {
|
|
|
67641
68783
|
};
|
|
67642
68784
|
function buildListParams(args5) {
|
|
67643
68785
|
const params2 = {};
|
|
67644
|
-
for (const [
|
|
67645
|
-
const value = args5[
|
|
68786
|
+
for (const [flag3, param] of Object.entries(PARAM_NAMES)) {
|
|
68787
|
+
const value = args5[flag3];
|
|
67646
68788
|
if (value !== void 0 && value !== "") {
|
|
67647
68789
|
params2[param] = String(value);
|
|
67648
68790
|
}
|
|
67649
68791
|
}
|
|
67650
68792
|
return params2;
|
|
67651
68793
|
}
|
|
67652
|
-
var listCommand20 =
|
|
68794
|
+
var listCommand20 = defineCommand226({
|
|
67653
68795
|
meta: {
|
|
67654
68796
|
name: "list",
|
|
67655
68797
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -67709,7 +68851,7 @@ var listCommand20 = defineCommand225({
|
|
|
67709
68851
|
});
|
|
67710
68852
|
|
|
67711
68853
|
// src/commands/testimonials/search.ts
|
|
67712
|
-
import { defineCommand as
|
|
68854
|
+
import { defineCommand as defineCommand227 } from "citty";
|
|
67713
68855
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
67714
68856
|
function languageBiasHint(results, requestedLanguage) {
|
|
67715
68857
|
if (requestedLanguage) {
|
|
@@ -67788,7 +68930,7 @@ function buildSearchRequest(query, args5) {
|
|
|
67788
68930
|
}
|
|
67789
68931
|
return body;
|
|
67790
68932
|
}
|
|
67791
|
-
var searchCommand3 =
|
|
68933
|
+
var searchCommand3 = defineCommand227({
|
|
67792
68934
|
meta: {
|
|
67793
68935
|
name: "search",
|
|
67794
68936
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -67852,7 +68994,7 @@ var searchCommand3 = defineCommand226({
|
|
|
67852
68994
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
67853
68995
|
|
|
67854
68996
|
// src/commands/testimonials/index.ts
|
|
67855
|
-
var testimonialsCommand =
|
|
68997
|
+
var testimonialsCommand = defineCommand228({
|
|
67856
68998
|
meta: {
|
|
67857
68999
|
name: "testimonials",
|
|
67858
69000
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -67874,10 +69016,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
67874
69016
|
});
|
|
67875
69017
|
|
|
67876
69018
|
// src/commands/videos/index.ts
|
|
67877
|
-
import { defineCommand as
|
|
69019
|
+
import { defineCommand as defineCommand236 } from "citty";
|
|
67878
69020
|
|
|
67879
69021
|
// src/commands/videos/delete.ts
|
|
67880
|
-
import { defineCommand as
|
|
69022
|
+
import { defineCommand as defineCommand229 } from "citty";
|
|
67881
69023
|
registerSchema({
|
|
67882
69024
|
command: "videos.delete",
|
|
67883
69025
|
description: "Delete a video by ID",
|
|
@@ -67891,7 +69033,7 @@ registerSchema({
|
|
|
67891
69033
|
}
|
|
67892
69034
|
}
|
|
67893
69035
|
});
|
|
67894
|
-
var deleteCommand4 =
|
|
69036
|
+
var deleteCommand4 = defineCommand229({
|
|
67895
69037
|
meta: {
|
|
67896
69038
|
name: "delete",
|
|
67897
69039
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -67932,7 +69074,7 @@ var deleteCommand4 = defineCommand228({
|
|
|
67932
69074
|
});
|
|
67933
69075
|
|
|
67934
69076
|
// src/commands/videos/describe.ts
|
|
67935
|
-
import { defineCommand as
|
|
69077
|
+
import { defineCommand as defineCommand230 } from "citty";
|
|
67936
69078
|
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.";
|
|
67937
69079
|
registerSchema({
|
|
67938
69080
|
command: "videos.describe",
|
|
@@ -67949,7 +69091,7 @@ registerSchema({
|
|
|
67949
69091
|
full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
|
|
67950
69092
|
}
|
|
67951
69093
|
});
|
|
67952
|
-
var describeCommand2 =
|
|
69094
|
+
var describeCommand2 = defineCommand230({
|
|
67953
69095
|
meta: {
|
|
67954
69096
|
name: "describe",
|
|
67955
69097
|
description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
|
|
@@ -68007,7 +69149,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
68007
69149
|
});
|
|
68008
69150
|
|
|
68009
69151
|
// src/commands/videos/get.ts
|
|
68010
|
-
import { defineCommand as
|
|
69152
|
+
import { defineCommand as defineCommand231 } from "citty";
|
|
68011
69153
|
registerSchema({
|
|
68012
69154
|
command: "videos.get",
|
|
68013
69155
|
description: "Get a single video by ID",
|
|
@@ -68015,7 +69157,7 @@ registerSchema({
|
|
|
68015
69157
|
id: { type: "string", description: "Video ID", required: true }
|
|
68016
69158
|
}
|
|
68017
69159
|
});
|
|
68018
|
-
var getCommand7 =
|
|
69160
|
+
var getCommand7 = defineCommand231({
|
|
68019
69161
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
68020
69162
|
args: {
|
|
68021
69163
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -68052,7 +69194,7 @@ var getCommand7 = defineCommand230({
|
|
|
68052
69194
|
});
|
|
68053
69195
|
|
|
68054
69196
|
// src/commands/videos/group.ts
|
|
68055
|
-
import { defineCommand as
|
|
69197
|
+
import { defineCommand as defineCommand232 } from "citty";
|
|
68056
69198
|
registerSchema({
|
|
68057
69199
|
command: "videos.group",
|
|
68058
69200
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -68061,7 +69203,7 @@ registerSchema({
|
|
|
68061
69203
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
68062
69204
|
}
|
|
68063
69205
|
});
|
|
68064
|
-
var groupCommand2 =
|
|
69206
|
+
var groupCommand2 = defineCommand232({
|
|
68065
69207
|
meta: {
|
|
68066
69208
|
name: "group",
|
|
68067
69209
|
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>"
|
|
@@ -68084,7 +69226,7 @@ var groupCommand2 = defineCommand231({
|
|
|
68084
69226
|
import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
|
|
68085
69227
|
import { tmpdir as tmpdir4 } from "os";
|
|
68086
69228
|
import path47 from "path";
|
|
68087
|
-
import { defineCommand as
|
|
69229
|
+
import { defineCommand as defineCommand233 } from "citty";
|
|
68088
69230
|
|
|
68089
69231
|
// src/lib/streamUpload.ts
|
|
68090
69232
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -68248,7 +69390,7 @@ registerSchema({
|
|
|
68248
69390
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
68249
69391
|
}
|
|
68250
69392
|
});
|
|
68251
|
-
var ingestCommand2 =
|
|
69393
|
+
var ingestCommand2 = defineCommand233({
|
|
68252
69394
|
meta: {
|
|
68253
69395
|
name: "ingest",
|
|
68254
69396
|
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"
|
|
@@ -68510,7 +69652,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
68510
69652
|
}
|
|
68511
69653
|
|
|
68512
69654
|
// src/commands/videos/search.ts
|
|
68513
|
-
import { defineCommand as
|
|
69655
|
+
import { defineCommand as defineCommand234 } from "citty";
|
|
68514
69656
|
registerSchema({
|
|
68515
69657
|
command: "videos.search",
|
|
68516
69658
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -68520,7 +69662,7 @@ registerSchema({
|
|
|
68520
69662
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
68521
69663
|
}
|
|
68522
69664
|
});
|
|
68523
|
-
var searchCommand4 =
|
|
69665
|
+
var searchCommand4 = defineCommand234({
|
|
68524
69666
|
meta: {
|
|
68525
69667
|
name: "search",
|
|
68526
69668
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -68572,7 +69714,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
68572
69714
|
// src/commands/videos/upload.ts
|
|
68573
69715
|
import { readFile as readFile33, stat as stat12 } from "fs/promises";
|
|
68574
69716
|
import { basename as basename3, extname as extname4 } from "path";
|
|
68575
|
-
import { defineCommand as
|
|
69717
|
+
import { defineCommand as defineCommand235 } from "citty";
|
|
68576
69718
|
var MIME_MAP = {
|
|
68577
69719
|
".mp4": "video/mp4",
|
|
68578
69720
|
".mov": "video/quicktime",
|
|
@@ -68614,7 +69756,7 @@ function detectContentType(filePath) {
|
|
|
68614
69756
|
function isRemoteUrl3(value) {
|
|
68615
69757
|
return /^https?:\/\//i.test(value);
|
|
68616
69758
|
}
|
|
68617
|
-
var uploadCommand2 =
|
|
69759
|
+
var uploadCommand2 = defineCommand235({
|
|
68618
69760
|
meta: {
|
|
68619
69761
|
name: "upload",
|
|
68620
69762
|
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"
|
|
@@ -68698,7 +69840,7 @@ var uploadCommand2 = defineCommand234({
|
|
|
68698
69840
|
});
|
|
68699
69841
|
|
|
68700
69842
|
// src/commands/videos/index.ts
|
|
68701
|
-
var videosCommand =
|
|
69843
|
+
var videosCommand = defineCommand236({
|
|
68702
69844
|
meta: {
|
|
68703
69845
|
name: "videos",
|
|
68704
69846
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
|
|
@@ -68727,10 +69869,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
68727
69869
|
});
|
|
68728
69870
|
|
|
68729
69871
|
// src/commands/winning-ads/index.ts
|
|
68730
|
-
import { defineCommand as
|
|
69872
|
+
import { defineCommand as defineCommand249 } from "citty";
|
|
68731
69873
|
|
|
68732
69874
|
// src/commands/winning-ads/advertisers.ts
|
|
68733
|
-
import { defineCommand as
|
|
69875
|
+
import { defineCommand as defineCommand237 } from "citty";
|
|
68734
69876
|
|
|
68735
69877
|
// src/commands/winning-ads/shared.ts
|
|
68736
69878
|
function splitList3(value) {
|
|
@@ -68783,7 +69925,7 @@ function advertiserNormalizer(record, full) {
|
|
|
68783
69925
|
last_synced_at: record.last_synced_at ?? null
|
|
68784
69926
|
};
|
|
68785
69927
|
}
|
|
68786
|
-
var advertisersCommand2 =
|
|
69928
|
+
var advertisersCommand2 = defineCommand237({
|
|
68787
69929
|
meta: {
|
|
68788
69930
|
name: "advertisers",
|
|
68789
69931
|
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'
|
|
@@ -68841,7 +69983,7 @@ var advertisersCommand2 = defineCommand236({
|
|
|
68841
69983
|
});
|
|
68842
69984
|
|
|
68843
69985
|
// src/commands/winning-ads/brief.ts
|
|
68844
|
-
import { defineCommand as
|
|
69986
|
+
import { defineCommand as defineCommand238 } from "citty";
|
|
68845
69987
|
registerSchema({
|
|
68846
69988
|
command: "winning-ads.brief",
|
|
68847
69989
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -68887,7 +70029,7 @@ function parseDna(raw) {
|
|
|
68887
70029
|
}
|
|
68888
70030
|
return parsed;
|
|
68889
70031
|
}
|
|
68890
|
-
var briefCommand =
|
|
70032
|
+
var briefCommand = defineCommand238({
|
|
68891
70033
|
meta: {
|
|
68892
70034
|
name: "brief",
|
|
68893
70035
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -68923,7 +70065,7 @@ var briefCommand = defineCommand237({
|
|
|
68923
70065
|
});
|
|
68924
70066
|
|
|
68925
70067
|
// src/commands/winning-ads/content.ts
|
|
68926
|
-
import { defineCommand as
|
|
70068
|
+
import { defineCommand as defineCommand239 } from "citty";
|
|
68927
70069
|
registerSchema({
|
|
68928
70070
|
command: "winning-ads.content",
|
|
68929
70071
|
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.",
|
|
@@ -68936,7 +70078,7 @@ registerSchema({
|
|
|
68936
70078
|
}
|
|
68937
70079
|
}
|
|
68938
70080
|
});
|
|
68939
|
-
var contentCommand =
|
|
70081
|
+
var contentCommand = defineCommand239({
|
|
68940
70082
|
meta: {
|
|
68941
70083
|
name: "content",
|
|
68942
70084
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -68985,7 +70127,7 @@ var contentCommand = defineCommand238({
|
|
|
68985
70127
|
});
|
|
68986
70128
|
|
|
68987
70129
|
// src/commands/winning-ads/feed.ts
|
|
68988
|
-
import { defineCommand as
|
|
70130
|
+
import { defineCommand as defineCommand240 } from "citty";
|
|
68989
70131
|
function buildFeedParams(input) {
|
|
68990
70132
|
const params2 = {};
|
|
68991
70133
|
const advertiser = splitList3(input.advertiser);
|
|
@@ -69037,7 +70179,7 @@ registerSchema({
|
|
|
69037
70179
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
69038
70180
|
}
|
|
69039
70181
|
});
|
|
69040
|
-
var feedCommand2 =
|
|
70182
|
+
var feedCommand2 = defineCommand240({
|
|
69041
70183
|
meta: {
|
|
69042
70184
|
name: "feed",
|
|
69043
70185
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -69122,7 +70264,7 @@ var feedCommand2 = defineCommand239({
|
|
|
69122
70264
|
});
|
|
69123
70265
|
|
|
69124
70266
|
// src/commands/winning-ads/follow.ts
|
|
69125
|
-
import { defineCommand as
|
|
70267
|
+
import { defineCommand as defineCommand241 } from "citty";
|
|
69126
70268
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
69127
70269
|
registerSchema({
|
|
69128
70270
|
command: "winning-ads.follow",
|
|
@@ -69137,7 +70279,7 @@ registerSchema({
|
|
|
69137
70279
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
69138
70280
|
}
|
|
69139
70281
|
});
|
|
69140
|
-
var followCommand =
|
|
70282
|
+
var followCommand = defineCommand241({
|
|
69141
70283
|
meta: {
|
|
69142
70284
|
name: "follow",
|
|
69143
70285
|
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'
|
|
@@ -69184,7 +70326,7 @@ var followCommand = defineCommand240({
|
|
|
69184
70326
|
});
|
|
69185
70327
|
|
|
69186
70328
|
// src/commands/winning-ads/follow-competitors.ts
|
|
69187
|
-
import { defineCommand as
|
|
70329
|
+
import { defineCommand as defineCommand242 } from "citty";
|
|
69188
70330
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
69189
70331
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
69190
70332
|
function buildFollowBatchBody(input) {
|
|
@@ -69217,7 +70359,7 @@ registerSchema({
|
|
|
69217
70359
|
}
|
|
69218
70360
|
}
|
|
69219
70361
|
});
|
|
69220
|
-
var followCompetitorsCommand =
|
|
70362
|
+
var followCompetitorsCommand = defineCommand242({
|
|
69221
70363
|
meta: {
|
|
69222
70364
|
name: "follow-competitors",
|
|
69223
70365
|
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"'
|
|
@@ -69292,7 +70434,7 @@ var followCompetitorsCommand = defineCommand241({
|
|
|
69292
70434
|
});
|
|
69293
70435
|
|
|
69294
70436
|
// src/commands/winning-ads/following.ts
|
|
69295
|
-
import { defineCommand as
|
|
70437
|
+
import { defineCommand as defineCommand243 } from "citty";
|
|
69296
70438
|
registerSchema({
|
|
69297
70439
|
command: "winning-ads.following",
|
|
69298
70440
|
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.",
|
|
@@ -69346,7 +70488,7 @@ function followingNormalizer(record, full) {
|
|
|
69346
70488
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
69347
70489
|
};
|
|
69348
70490
|
}
|
|
69349
|
-
var followingCommand =
|
|
70491
|
+
var followingCommand = defineCommand243({
|
|
69350
70492
|
meta: {
|
|
69351
70493
|
name: "following",
|
|
69352
70494
|
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"
|
|
@@ -69382,7 +70524,7 @@ var followingCommand = defineCommand242({
|
|
|
69382
70524
|
});
|
|
69383
70525
|
|
|
69384
70526
|
// src/commands/winning-ads/patterns.ts
|
|
69385
|
-
import { defineCommand as
|
|
70527
|
+
import { defineCommand as defineCommand244 } from "citty";
|
|
69386
70528
|
registerSchema({
|
|
69387
70529
|
command: "winning-ads.patterns",
|
|
69388
70530
|
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.",
|
|
@@ -69421,7 +70563,7 @@ function discriminatorRow(record) {
|
|
|
69421
70563
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
69422
70564
|
};
|
|
69423
70565
|
}
|
|
69424
|
-
var patternsCommand =
|
|
70566
|
+
var patternsCommand = defineCommand244({
|
|
69425
70567
|
meta: {
|
|
69426
70568
|
name: "patterns",
|
|
69427
70569
|
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"
|
|
@@ -69477,7 +70619,7 @@ var patternsCommand = defineCommand243({
|
|
|
69477
70619
|
});
|
|
69478
70620
|
|
|
69479
70621
|
// src/commands/winning-ads/search.ts
|
|
69480
|
-
import { defineCommand as
|
|
70622
|
+
import { defineCommand as defineCommand245 } from "citty";
|
|
69481
70623
|
registerSchema({
|
|
69482
70624
|
command: "winning-ads.search",
|
|
69483
70625
|
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.",
|
|
@@ -69615,7 +70757,7 @@ function reportSearchError(err) {
|
|
|
69615
70757
|
}
|
|
69616
70758
|
reportError2(err);
|
|
69617
70759
|
}
|
|
69618
|
-
var searchCommand5 =
|
|
70760
|
+
var searchCommand5 = defineCommand245({
|
|
69619
70761
|
meta: {
|
|
69620
70762
|
name: "search",
|
|
69621
70763
|
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"
|
|
@@ -69735,7 +70877,7 @@ var searchCommand5 = defineCommand244({
|
|
|
69735
70877
|
});
|
|
69736
70878
|
|
|
69737
70879
|
// src/commands/winning-ads/seeds.ts
|
|
69738
|
-
import { defineCommand as
|
|
70880
|
+
import { defineCommand as defineCommand246 } from "citty";
|
|
69739
70881
|
function leanRow(r) {
|
|
69740
70882
|
return {
|
|
69741
70883
|
key: r.key,
|
|
@@ -69763,7 +70905,7 @@ function makeSeedCommand(opts) {
|
|
|
69763
70905
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
69764
70906
|
}
|
|
69765
70907
|
});
|
|
69766
|
-
return
|
|
70908
|
+
return defineCommand246({
|
|
69767
70909
|
meta: { name: opts.name, description: opts.description },
|
|
69768
70910
|
args: {
|
|
69769
70911
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -69812,7 +70954,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
69812
70954
|
});
|
|
69813
70955
|
|
|
69814
70956
|
// src/commands/winning-ads/unfollow.ts
|
|
69815
|
-
import { defineCommand as
|
|
70957
|
+
import { defineCommand as defineCommand247 } from "citty";
|
|
69816
70958
|
registerSchema({
|
|
69817
70959
|
command: "winning-ads.unfollow",
|
|
69818
70960
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -69820,7 +70962,7 @@ registerSchema({
|
|
|
69820
70962
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
69821
70963
|
}
|
|
69822
70964
|
});
|
|
69823
|
-
var unfollowCommand =
|
|
70965
|
+
var unfollowCommand = defineCommand247({
|
|
69824
70966
|
meta: {
|
|
69825
70967
|
name: "unfollow",
|
|
69826
70968
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -69841,7 +70983,7 @@ var unfollowCommand = defineCommand246({
|
|
|
69841
70983
|
});
|
|
69842
70984
|
|
|
69843
70985
|
// src/commands/winning-ads/winners.ts
|
|
69844
|
-
import { defineCommand as
|
|
70986
|
+
import { defineCommand as defineCommand248 } from "citty";
|
|
69845
70987
|
registerSchema({
|
|
69846
70988
|
command: "winning-ads.winners",
|
|
69847
70989
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -69851,7 +70993,7 @@ registerSchema({
|
|
|
69851
70993
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
69852
70994
|
}
|
|
69853
70995
|
});
|
|
69854
|
-
var winnersCommand =
|
|
70996
|
+
var winnersCommand = defineCommand248({
|
|
69855
70997
|
meta: {
|
|
69856
70998
|
name: "winners",
|
|
69857
70999
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -69901,7 +71043,7 @@ var winnersCommand = defineCommand247({
|
|
|
69901
71043
|
});
|
|
69902
71044
|
|
|
69903
71045
|
// src/commands/winning-ads/index.ts
|
|
69904
|
-
var winningAdsCommand =
|
|
71046
|
+
var winningAdsCommand = defineCommand249({
|
|
69905
71047
|
meta: {
|
|
69906
71048
|
name: "winning-ads",
|
|
69907
71049
|
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.
|
|
@@ -70093,16 +71235,16 @@ function commandFor(root, argv) {
|
|
|
70093
71235
|
return resolved ? command : null;
|
|
70094
71236
|
}
|
|
70095
71237
|
function suggestFlag(unknown, command) {
|
|
70096
|
-
const
|
|
70097
|
-
if (!
|
|
71238
|
+
const flag3 = closestFlag(unknown, command);
|
|
71239
|
+
if (!flag3) {
|
|
70098
71240
|
return null;
|
|
70099
71241
|
}
|
|
70100
71242
|
const args5 = argsOf(command) ?? {};
|
|
70101
|
-
const name =
|
|
71243
|
+
const name = flag3.slice(2);
|
|
70102
71244
|
const def = args5[name] ?? args5[camel(name)];
|
|
70103
71245
|
const described = def && typeof def === "object" ? def.description : void 0;
|
|
70104
71246
|
const description = typeof described === "string" ? described.split(/(?<!\b(?:e\.g|i\.e|vs))\.\s/)[0]?.trim().replace(/\.$/, "") : "";
|
|
70105
|
-
return description ? { flag:
|
|
71247
|
+
return description ? { flag: flag3, description } : { flag: flag3 };
|
|
70106
71248
|
}
|
|
70107
71249
|
function suggestionText(suggestion) {
|
|
70108
71250
|
if (!suggestion) {
|
|
@@ -70120,7 +71262,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
|
70120
71262
|
message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
70121
71263
|
fix: {
|
|
70122
71264
|
action: hasSchema ? "check_schema" : "check_help",
|
|
70123
|
-
explanation: (unknown.some((
|
|
71265
|
+
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.`
|
|
70124
71266
|
},
|
|
70125
71267
|
retryable: false
|
|
70126
71268
|
}
|
|
@@ -70178,13 +71320,13 @@ function declaredArg(command, name) {
|
|
|
70178
71320
|
}
|
|
70179
71321
|
function envelopeRequests(argv) {
|
|
70180
71322
|
const end = argv.indexOf("--");
|
|
70181
|
-
const
|
|
71323
|
+
const limit2 = end === -1 ? argv.length : end;
|
|
70182
71324
|
const found = [];
|
|
70183
|
-
for (let index = 0; index <
|
|
71325
|
+
for (let index = 0; index < limit2; index++) {
|
|
70184
71326
|
const token = argv[index];
|
|
70185
71327
|
if (token === `${FLAG}=${ENVELOPE}`) {
|
|
70186
71328
|
found.push({ index, length: 1 });
|
|
70187
|
-
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 <
|
|
71329
|
+
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit2) {
|
|
70188
71330
|
found.push({ index, length: 2 });
|
|
70189
71331
|
index++;
|
|
70190
71332
|
}
|
|
@@ -70228,7 +71370,7 @@ function getCliVersion() {
|
|
|
70228
71370
|
}
|
|
70229
71371
|
|
|
70230
71372
|
// src/cli.ts
|
|
70231
|
-
var main =
|
|
71373
|
+
var main = defineCommand250({
|
|
70232
71374
|
meta: {
|
|
70233
71375
|
name: "baker",
|
|
70234
71376
|
version: getCliVersion(),
|