@koda-sl/baker-cli 0.373.0-dev.56c2ad392 → 0.373.0-dev.5cf4f1409
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -19
- package/dist/cli.js +477 -1377
- 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 defineCommand249, 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 limit = end === -1 ? argv.length : end;
|
|
165
|
+
return argv.flatMap((token, index) => index >= limit ? [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((days) => days >= 14 && days <= 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 days = rule.timeFrame.timeSpan.duration;
|
|
1582
|
+
if (!allowed.includes(days)) {
|
|
1583
|
+
problems.push(`lookback ${days} 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}`));
|
|
@@ -7143,12 +7143,12 @@ function parseClause(clause) {
|
|
|
7143
7143
|
return { error: `"${clause}" has no operator this understands. ${EXPRESSION_HELP}` };
|
|
7144
7144
|
}
|
|
7145
7145
|
function parseConditionsExpression(expression) {
|
|
7146
|
-
const
|
|
7147
|
-
if ("error" in
|
|
7148
|
-
return { ok: false, error:
|
|
7146
|
+
const split = splitClauses(expression);
|
|
7147
|
+
if ("error" in split) {
|
|
7148
|
+
return { ok: false, error: split.error };
|
|
7149
7149
|
}
|
|
7150
7150
|
const rules = [];
|
|
7151
|
-
for (const clause of
|
|
7151
|
+
for (const clause of split.clauses) {
|
|
7152
7152
|
if (clause.length === 0) {
|
|
7153
7153
|
return { ok: false, error: `An empty rule. ${EXPRESSION_HELP}` };
|
|
7154
7154
|
}
|
|
@@ -7161,7 +7161,7 @@ function parseConditionsExpression(expression) {
|
|
|
7161
7161
|
if (rules.length > MAX_CONDITION_RULES) {
|
|
7162
7162
|
return { ok: false, error: `At most ${MAX_CONDITION_RULES} rules.` };
|
|
7163
7163
|
}
|
|
7164
|
-
return { ok: true, conditions: { match:
|
|
7164
|
+
return { ok: true, conditions: { match: split.match, rules } };
|
|
7165
7165
|
}
|
|
7166
7166
|
|
|
7167
7167
|
// ../api/src/scheduledAgents.ts
|
|
@@ -8618,12 +8618,12 @@ function advisoryHint(name, description) {
|
|
|
8618
8618
|
return executable ? { kind: "executable", ...executable } : null;
|
|
8619
8619
|
}
|
|
8620
8620
|
var ACTIONS_LIST_DEFAULT_LIMIT = 500;
|
|
8621
|
-
function buildListHints({ returned, limit
|
|
8622
|
-
if (returned <
|
|
8621
|
+
function buildListHints({ returned, limit }) {
|
|
8622
|
+
if (returned < limit) {
|
|
8623
8623
|
return [];
|
|
8624
8624
|
}
|
|
8625
8625
|
return [
|
|
8626
|
-
`This list is capped at ${
|
|
8626
|
+
`This list is capped at ${limit} 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 ${limit * 2} (or narrow with --status / --search).`
|
|
8627
8627
|
];
|
|
8628
8628
|
}
|
|
8629
8629
|
|
|
@@ -9402,9 +9402,9 @@ function resolveWindow(args5) {
|
|
|
9402
9402
|
const todayStart = startOfLocalDay(new Date(now));
|
|
9403
9403
|
return { fromMs: todayStart - DAY_MS, toMs: todayStart };
|
|
9404
9404
|
}
|
|
9405
|
-
const
|
|
9406
|
-
if (
|
|
9407
|
-
return { fromMs: now - Number(
|
|
9405
|
+
const days = /^(\d+)d$/.exec(since);
|
|
9406
|
+
if (days) {
|
|
9407
|
+
return { fromMs: now - Number(days[1]) * DAY_MS, toMs: now };
|
|
9408
9408
|
}
|
|
9409
9409
|
return failValidation(`--since must be one of: today | yesterday | <N>d (e.g. 7d). Got: ${since}`);
|
|
9410
9410
|
}
|
|
@@ -9802,15 +9802,15 @@ import { defineCommand as defineCommand19 } from "citty";
|
|
|
9802
9802
|
function listed(resources) {
|
|
9803
9803
|
return resources.map((resource) => resource.label ? `${resource.id} (${resource.label})` : resource.id).join("; ");
|
|
9804
9804
|
}
|
|
9805
|
-
function connectedResourceHints({ plural, singular, flag:
|
|
9805
|
+
function connectedResourceHints({ plural, singular, flag: flag2, resources }) {
|
|
9806
9806
|
if (resources.length === 0) {
|
|
9807
9807
|
return [];
|
|
9808
9808
|
}
|
|
9809
9809
|
if (resources.length === 1) {
|
|
9810
|
-
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 ${flag2}.`];
|
|
9811
9811
|
}
|
|
9812
9812
|
return [
|
|
9813
|
-
`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 ${flag2} \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.`
|
|
9814
9814
|
];
|
|
9815
9815
|
}
|
|
9816
9816
|
|
|
@@ -10033,8 +10033,8 @@ var CHANGE_SCOPE_MAX_DAYS = {
|
|
|
10033
10033
|
};
|
|
10034
10034
|
var DEFAULT_CHANGE_DAYS = 7;
|
|
10035
10035
|
var MAX_CHANGE_DAYS = CHANGE_SCOPE_MAX_DAYS.summary;
|
|
10036
|
-
function isChangeLookbackWithinReach(
|
|
10037
|
-
return
|
|
10036
|
+
function isChangeLookbackWithinReach(days, scope) {
|
|
10037
|
+
return days <= CHANGE_SCOPE_MAX_DAYS[scope];
|
|
10038
10038
|
}
|
|
10039
10039
|
|
|
10040
10040
|
// ../api/src/ads-google/geo-constants.ts
|
|
@@ -10467,8 +10467,8 @@ function equivalentBetween(literal, now) {
|
|
|
10467
10467
|
const unit = rolling[2];
|
|
10468
10468
|
if (n < 1) return null;
|
|
10469
10469
|
if (unit === "DAYS" || unit === "WEEKS") {
|
|
10470
|
-
const
|
|
10471
|
-
return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() -
|
|
10470
|
+
const days = unit === "DAYS" ? n : n * 7;
|
|
10471
|
+
return range(utcDate(year, today.getUTCMonth(), today.getUTCDate() - days), yesterday);
|
|
10472
10472
|
}
|
|
10473
10473
|
const months = unit === "MONTHS" ? n : n * 12;
|
|
10474
10474
|
return range(monthsBefore(today, months), yesterday);
|
|
@@ -10514,13 +10514,13 @@ function resolveChangesWindow(input) {
|
|
|
10514
10514
|
}
|
|
10515
10515
|
};
|
|
10516
10516
|
}
|
|
10517
|
-
const
|
|
10518
|
-
if (!Number.isInteger(
|
|
10517
|
+
const days = input.days ?? DEFAULT_CHANGE_DAYS;
|
|
10518
|
+
if (!Number.isInteger(days) || days < 1) {
|
|
10519
10519
|
return {
|
|
10520
10520
|
ok: false,
|
|
10521
10521
|
error: {
|
|
10522
10522
|
code: "INVALID_LOOKBACK",
|
|
10523
|
-
message: `--days must be a whole number of days, got '${
|
|
10523
|
+
message: `--days must be a whole number of days, got '${days}'.`,
|
|
10524
10524
|
fix: {
|
|
10525
10525
|
action: "retry_with_flag",
|
|
10526
10526
|
explanation: `Pass --days as a positive integer, e.g. --days ${DEFAULT_CHANGE_DAYS}.`
|
|
@@ -10528,32 +10528,32 @@ function resolveChangesWindow(input) {
|
|
|
10528
10528
|
}
|
|
10529
10529
|
};
|
|
10530
10530
|
}
|
|
10531
|
-
if (!isChangeLookbackWithinReach(
|
|
10532
|
-
return { ok: false, error: lookbackTooLong(scope,
|
|
10531
|
+
if (!isChangeLookbackWithinReach(days, scope)) {
|
|
10532
|
+
return { ok: false, error: lookbackTooLong(scope, days, CHANGE_SCOPE_MAX_DAYS[scope]) };
|
|
10533
10533
|
}
|
|
10534
|
-
return { ok: true, scope, days
|
|
10534
|
+
return { ok: true, scope, days, hints: hintsFor(scope, days) };
|
|
10535
10535
|
}
|
|
10536
|
-
function lookbackTooLong(scope,
|
|
10537
|
-
if (scope === "detail" &&
|
|
10536
|
+
function lookbackTooLong(scope, days, max) {
|
|
10537
|
+
if (scope === "detail" && days <= CHANGE_SCOPE_MAX_DAYS.summary) {
|
|
10538
10538
|
return {
|
|
10539
10539
|
code: "LOOKBACK_TOO_LONG",
|
|
10540
|
-
message: `Google keeps field-level change detail for ${max} days only; ${
|
|
10540
|
+
message: `Google keeps field-level change detail for ${max} days only; ${days} days is outside that window.`,
|
|
10541
10541
|
fix: {
|
|
10542
10542
|
action: "narrow_date_range",
|
|
10543
|
-
explanation: `Re-run with --scope summary --days ${
|
|
10543
|
+
explanation: `Re-run with --scope summary --days ${days} 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.`
|
|
10544
10544
|
}
|
|
10545
10545
|
};
|
|
10546
10546
|
}
|
|
10547
10547
|
return {
|
|
10548
10548
|
code: "LOOKBACK_TOO_LONG",
|
|
10549
|
-
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; ${days} days is outside that window.`,
|
|
10550
10550
|
fix: {
|
|
10551
10551
|
action: "use_different_resource",
|
|
10552
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.`
|
|
10553
10553
|
}
|
|
10554
10554
|
};
|
|
10555
10555
|
}
|
|
10556
|
-
function hintsFor(scope,
|
|
10556
|
+
function hintsFor(scope, days) {
|
|
10557
10557
|
const hints2 = [];
|
|
10558
10558
|
if (scope === "detail") {
|
|
10559
10559
|
hints2.push(
|
|
@@ -10563,7 +10563,7 @@ function hintsFor(scope, days2) {
|
|
|
10563
10563
|
hints2.push(
|
|
10564
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."
|
|
10565
10565
|
);
|
|
10566
|
-
if (
|
|
10566
|
+
if (days > CHANGE_SCOPE_MAX_DAYS.detail) {
|
|
10567
10567
|
hints2.push(
|
|
10568
10568
|
`Changes inside the last ${CHANGE_SCOPE_MAX_DAYS.detail} days also have field-level detail \u2014 re-run with --scope detail for those.`
|
|
10569
10569
|
);
|
|
@@ -11009,11 +11009,11 @@ var CORRECTION_RULES = [
|
|
|
11009
11009
|
{
|
|
11010
11010
|
matchApiError: /changeEventError\W{0,4}START_DATE_TOO_OLD/i,
|
|
11011
11011
|
fix: (ctx) => {
|
|
11012
|
-
const
|
|
11012
|
+
const limit = ctx.originalQuery.match(/LIMIT\s+(\d+)/i)?.[1] ?? "50";
|
|
11013
11013
|
const requested = ctx.originalQuery.match(/change_date_time\s*>=\s*'([^']+)'/i)?.[1]?.slice(0, 10);
|
|
11014
11014
|
const oldestStart = new Date(Date.now() - 89 * 24 * 60 * 60 * 1e3).toISOString().slice(0, 10);
|
|
11015
11015
|
const start = requested && requested > oldestStart ? requested : oldestStart;
|
|
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 ${
|
|
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 ${limit}`;
|
|
11017
11017
|
return {
|
|
11018
11018
|
action: "use_different_resource",
|
|
11019
11019
|
correctedCommand: buildCommand(corrected, ctx),
|
|
@@ -11405,8 +11405,8 @@ import { defineCommand as defineCommand22 } from "citty";
|
|
|
11405
11405
|
import { readFileSync as readFileSync2 } from "fs";
|
|
11406
11406
|
|
|
11407
11407
|
// src/lib/repeatedFlags.ts
|
|
11408
|
-
function repeatedFlagValues(rawArgs,
|
|
11409
|
-
const long = `--${
|
|
11408
|
+
function repeatedFlagValues(rawArgs, flag2) {
|
|
11409
|
+
const long = `--${flag2}`;
|
|
11410
11410
|
const inline = `${long}=`;
|
|
11411
11411
|
const values = [];
|
|
11412
11412
|
for (let i = 0; i < rawArgs.length; i++) {
|
|
@@ -11424,9 +11424,9 @@ function repeatedFlagValues(rawArgs, flag3) {
|
|
|
11424
11424
|
}
|
|
11425
11425
|
return values;
|
|
11426
11426
|
}
|
|
11427
|
-
function repeatedValues(rawArgs,
|
|
11427
|
+
function repeatedValues(rawArgs, flag2, parsed) {
|
|
11428
11428
|
if (rawArgs !== void 0) {
|
|
11429
|
-
const fromLine = repeatedFlagValues(rawArgs,
|
|
11429
|
+
const fromLine = repeatedFlagValues(rawArgs, flag2);
|
|
11430
11430
|
if (fromLine.length > 0) return fromLine;
|
|
11431
11431
|
}
|
|
11432
11432
|
if (Array.isArray(parsed)) return parsed.filter((v) => typeof v === "string");
|
|
@@ -11452,8 +11452,8 @@ function booleanWordPositionalError(args5, entity) {
|
|
|
11452
11452
|
}
|
|
11453
11453
|
const value = word.toLowerCase();
|
|
11454
11454
|
const raised = Object.keys(args5).filter((key) => key !== "_" && args5[key] === true);
|
|
11455
|
-
const named = raised.length > 0 ? raised.map((
|
|
11456
|
-
const fix = raised.length > 0 ? raised.map((
|
|
11455
|
+
const named = raised.length > 0 ? raised.map((flag2) => `--${flag2}`).join(" or ") : "a boolean flag";
|
|
11456
|
+
const fix = raised.length > 0 ? raised.map((flag2) => `--${flag2}=${value}`).join(" or ") : `--<flag>=${value}`;
|
|
11457
11457
|
const negated = raised.length === 1 && value === "false" ? ` (or --no-${raised[0]})` : "";
|
|
11458
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}.`;
|
|
11459
11459
|
}
|
|
@@ -12061,19 +12061,19 @@ function requireTarget(args5, entity) {
|
|
|
12061
12061
|
}
|
|
12062
12062
|
return target2;
|
|
12063
12063
|
}
|
|
12064
|
-
function requireStringFlag(value,
|
|
12064
|
+
function requireStringFlag(value, flag2) {
|
|
12065
12065
|
if (typeof value !== "string" || value.length === 0) {
|
|
12066
|
-
failWriteValidation(`${
|
|
12066
|
+
failWriteValidation(`${flag2} is required`);
|
|
12067
12067
|
}
|
|
12068
12068
|
return value;
|
|
12069
12069
|
}
|
|
12070
|
-
function microsFlag(value,
|
|
12070
|
+
function microsFlag(value, flag2) {
|
|
12071
12071
|
if (value === void 0 || value === null || value === "") {
|
|
12072
12072
|
return void 0;
|
|
12073
12073
|
}
|
|
12074
12074
|
const num4 = Number(value);
|
|
12075
12075
|
if (Number.isNaN(num4) || num4 <= 0) {
|
|
12076
|
-
failWriteValidation(`${
|
|
12076
|
+
failWriteValidation(`${flag2} must be a positive amount (major currency units, e.g. 50 or 50.00)`);
|
|
12077
12077
|
}
|
|
12078
12078
|
return toMicros(num4);
|
|
12079
12079
|
}
|
|
@@ -13000,13 +13000,13 @@ function buildStatusScope(statusFields, includePaused) {
|
|
|
13000
13000
|
}
|
|
13001
13001
|
function expandPreset(preset, params2, now = /* @__PURE__ */ new Date()) {
|
|
13002
13002
|
const dateRange = params2.dateRange ?? preset.defaultDateRange;
|
|
13003
|
-
const
|
|
13003
|
+
const limit = params2.limit ?? preset.defaultLimit;
|
|
13004
13004
|
if (preset.gaqlTemplate.includes("{dateRange}") && !isValidDateRange(dateRange)) {
|
|
13005
13005
|
return { query: "", dateRangeError: dateRangeError(dateRange, now) };
|
|
13006
13006
|
}
|
|
13007
13007
|
const statusScope = buildStatusScope(preset.statusFields, params2.includePaused ?? false);
|
|
13008
13008
|
const range = dateRange.trim();
|
|
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(
|
|
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(limit)).replace(/\{statusScope\}/g, statusScope);
|
|
13010
13010
|
return { query };
|
|
13011
13011
|
}
|
|
13012
13012
|
|
|
@@ -13126,7 +13126,7 @@ function addRequiredAncestorFields(query) {
|
|
|
13126
13126
|
]
|
|
13127
13127
|
};
|
|
13128
13128
|
}
|
|
13129
|
-
function applyAutoFixes(query,
|
|
13129
|
+
function applyAutoFixes(query, limit) {
|
|
13130
13130
|
let corrected = query;
|
|
13131
13131
|
const warnings = [];
|
|
13132
13132
|
if (/(?<![\w.])keyword\.text\b/.test(corrected)) {
|
|
@@ -13157,7 +13157,7 @@ function applyAutoFixes(query, limit2) {
|
|
|
13157
13157
|
warnings.push({ code: "ENUM_CORRECTED", message: "ad_group.status ACTIVE \u2192 ENABLED" });
|
|
13158
13158
|
}
|
|
13159
13159
|
if (!/\bLIMIT\b/i.test(corrected)) {
|
|
13160
|
-
const effectiveLimit =
|
|
13160
|
+
const effectiveLimit = limit ?? 200;
|
|
13161
13161
|
corrected = `${corrected.trimEnd()} LIMIT ${effectiveLimit}`;
|
|
13162
13162
|
if (!isSingleRowRead(corrected)) {
|
|
13163
13163
|
warnings.push({ code: "AUTO_LIMIT", message: `Added LIMIT ${effectiveLimit}. Use --limit to override.` });
|
|
@@ -13275,7 +13275,7 @@ function rejectContainsCall(query, customerId) {
|
|
|
13275
13275
|
}
|
|
13276
13276
|
};
|
|
13277
13277
|
}
|
|
13278
|
-
function validatePreflight(query, customerId,
|
|
13278
|
+
function validatePreflight(query, customerId, limit) {
|
|
13279
13279
|
const warnings = [];
|
|
13280
13280
|
const corrected = query;
|
|
13281
13281
|
const firstWord = corrected.trim().split(/\s+/)[0]?.toUpperCase();
|
|
@@ -13351,7 +13351,7 @@ function validatePreflight(query, customerId, limit2) {
|
|
|
13351
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."
|
|
13352
13352
|
});
|
|
13353
13353
|
}
|
|
13354
|
-
const { query: autoFixed, warnings: autoFixWarnings } = applyAutoFixes(corrected,
|
|
13354
|
+
const { query: autoFixed, warnings: autoFixWarnings } = applyAutoFixes(corrected, limit);
|
|
13355
13355
|
warnings.push(...autoFixWarnings);
|
|
13356
13356
|
const analysis = analyzeServingChain(autoFixed);
|
|
13357
13357
|
if (!analysis) return { valid: true, correctedQuery: autoFixed, warnings };
|
|
@@ -13620,12 +13620,12 @@ function writeRowsToFile(filePath, rows, fields, append) {
|
|
|
13620
13620
|
writeFileSync(filePath, JSON.stringify(rows, null, 2), "utf-8");
|
|
13621
13621
|
}
|
|
13622
13622
|
}
|
|
13623
|
-
function effectiveRowLimit(finalQuery,
|
|
13623
|
+
function effectiveRowLimit(finalQuery, limit, all = false) {
|
|
13624
13624
|
if (isSingleRowRead(finalQuery)) return void 0;
|
|
13625
13625
|
const match = finalQuery.match(/\bLIMIT\s+(\d+)/i);
|
|
13626
13626
|
const statementLimit = match?.[1] ? Number(match[1]) : void 0;
|
|
13627
13627
|
if (all) return statementLimit;
|
|
13628
|
-
return statementLimit === void 0 ?
|
|
13628
|
+
return statementLimit === void 0 ? limit : Math.min(limit, statementLimit);
|
|
13629
13629
|
}
|
|
13630
13630
|
function warningLines(warnings, format) {
|
|
13631
13631
|
return warnings.map((w) => {
|
|
@@ -13743,7 +13743,7 @@ function outputResults(rows, fieldDescs, warnings, args5, cached, read) {
|
|
|
13743
13743
|
}
|
|
13744
13744
|
writeRows(format, rows, resultColumns(read.gaql, rows), warningLines(allWarnings, format));
|
|
13745
13745
|
}
|
|
13746
|
-
function resolveGaql(args5,
|
|
13746
|
+
function resolveGaql(args5, limit) {
|
|
13747
13747
|
if (args5.preset) {
|
|
13748
13748
|
const preset = getPreset(args5.preset);
|
|
13749
13749
|
if (!preset) {
|
|
@@ -13756,7 +13756,7 @@ function resolveGaql(args5, limit2) {
|
|
|
13756
13756
|
}
|
|
13757
13757
|
const expanded = expandPreset(preset, {
|
|
13758
13758
|
dateRange: args5["date-range"],
|
|
13759
|
-
limit
|
|
13759
|
+
limit,
|
|
13760
13760
|
includePaused: Boolean(args5["include-paused"])
|
|
13761
13761
|
});
|
|
13762
13762
|
if (expanded.dateRangeError) {
|
|
@@ -13908,8 +13908,8 @@ async function fetchAllPages(gaql, body, args5, servingOptions) {
|
|
|
13908
13908
|
fileColumns: fileColumns ?? []
|
|
13909
13909
|
};
|
|
13910
13910
|
}
|
|
13911
|
-
async function executeQuery(finalQuery, args5, customerId,
|
|
13912
|
-
const body = { customerId, query: finalQuery, pageSize:
|
|
13911
|
+
async function executeQuery(finalQuery, args5, customerId, limit, warnings, useCache, cacheKey) {
|
|
13912
|
+
const body = { customerId, query: finalQuery, pageSize: limit };
|
|
13913
13913
|
const managerId = getManagerIdForCustomer(customerId);
|
|
13914
13914
|
if (managerId) body.managerId = managerId;
|
|
13915
13915
|
if (args5.cursor) body.pageToken = args5.cursor;
|
|
@@ -13924,7 +13924,7 @@ async function executeQuery(finalQuery, args5, customerId, limit2, warnings, use
|
|
|
13924
13924
|
if (args5.out) {
|
|
13925
13925
|
const truncation = completenessWarnings({
|
|
13926
13926
|
rowCount: totalRowsWritten,
|
|
13927
|
-
effectiveLimit: effectiveRowLimit(finalQuery,
|
|
13927
|
+
effectiveLimit: effectiveRowLimit(finalQuery, limit, Boolean(args5.all)),
|
|
13928
13928
|
all: Boolean(args5.all),
|
|
13929
13929
|
hasMore: Boolean(lastPageToken)
|
|
13930
13930
|
});
|
|
@@ -13966,7 +13966,7 @@ async function executeQuery(finalQuery, args5, customerId, limit2, warnings, use
|
|
|
13966
13966
|
false,
|
|
13967
13967
|
{
|
|
13968
13968
|
gaql: finalQuery,
|
|
13969
|
-
effectiveLimit: effectiveRowLimit(finalQuery,
|
|
13969
|
+
effectiveLimit: effectiveRowLimit(finalQuery, limit, Boolean(args5.all)),
|
|
13970
13970
|
all: Boolean(args5.all),
|
|
13971
13971
|
nextCursor: lastPageToken
|
|
13972
13972
|
}
|
|
@@ -13978,8 +13978,8 @@ function shouldReadCache(args5) {
|
|
|
13978
13978
|
var DEFAULT_QUERY_LIMIT = 200;
|
|
13979
13979
|
function parseQueryLimit(raw) {
|
|
13980
13980
|
if (raw === void 0 || raw === null || raw === "") return { ok: true, limit: DEFAULT_QUERY_LIMIT };
|
|
13981
|
-
const
|
|
13982
|
-
if (Number.isInteger(
|
|
13981
|
+
const limit = Number(raw);
|
|
13982
|
+
if (Number.isInteger(limit) && limit >= 1 && limit <= GOOGLE_ADS_QUERY_MAX_PAGE_SIZE) return { ok: true, limit };
|
|
13983
13983
|
return {
|
|
13984
13984
|
ok: false,
|
|
13985
13985
|
error: {
|
|
@@ -14002,13 +14002,13 @@ async function validateArgs(args5) {
|
|
|
14002
14002
|
writeAdsJson(parsedLimit.error);
|
|
14003
14003
|
process.exit(1);
|
|
14004
14004
|
}
|
|
14005
|
-
const { limit
|
|
14005
|
+
const { limit } = parsedLimit;
|
|
14006
14006
|
const customerId = await resolveCustomerId(args5);
|
|
14007
|
-
const gaql = resolveGaql(args5,
|
|
14007
|
+
const gaql = resolveGaql(args5, limit);
|
|
14008
14008
|
if (!gaql) {
|
|
14009
14009
|
process.exit(1);
|
|
14010
14010
|
}
|
|
14011
|
-
const preflight = validatePreflight(gaql, customerId,
|
|
14011
|
+
const preflight = validatePreflight(gaql, customerId, limit);
|
|
14012
14012
|
if (!preflight.valid && preflight.error) {
|
|
14013
14013
|
writeAdsJson(preflight.error);
|
|
14014
14014
|
process.exit(1);
|
|
@@ -14016,7 +14016,7 @@ async function validateArgs(args5) {
|
|
|
14016
14016
|
const finalQuery = preflight.correctedQuery ?? gaql;
|
|
14017
14017
|
return {
|
|
14018
14018
|
customerId,
|
|
14019
|
-
limit
|
|
14019
|
+
limit,
|
|
14020
14020
|
finalQuery,
|
|
14021
14021
|
warnings: [...preflight.warnings, ...servingScopeWarnings(args5, finalQuery)],
|
|
14022
14022
|
useCache: !args5["no-cache"],
|
|
@@ -14093,7 +14093,7 @@ Examples:
|
|
|
14093
14093
|
}
|
|
14094
14094
|
const validated = await validateArgs(args5);
|
|
14095
14095
|
if (!validated) return;
|
|
14096
|
-
const { customerId, limit
|
|
14096
|
+
const { customerId, limit, finalQuery, warnings, useCache, cacheKey } = validated;
|
|
14097
14097
|
if (shouldReadCache(args5)) {
|
|
14098
14098
|
const cached = cacheGet("queries", cacheKey);
|
|
14099
14099
|
if (cached) {
|
|
@@ -14111,7 +14111,7 @@ Examples:
|
|
|
14111
14111
|
true,
|
|
14112
14112
|
{
|
|
14113
14113
|
gaql: finalQuery,
|
|
14114
|
-
effectiveLimit: effectiveRowLimit(finalQuery,
|
|
14114
|
+
effectiveLimit: effectiveRowLimit(finalQuery, limit, Boolean(args5.all)),
|
|
14115
14115
|
all: Boolean(args5.all)
|
|
14116
14116
|
}
|
|
14117
14117
|
);
|
|
@@ -14119,7 +14119,7 @@ Examples:
|
|
|
14119
14119
|
}
|
|
14120
14120
|
}
|
|
14121
14121
|
try {
|
|
14122
|
-
await executeQuery(finalQuery, args5, customerId,
|
|
14122
|
+
await executeQuery(finalQuery, args5, customerId, limit, warnings, useCache, cacheKey);
|
|
14123
14123
|
} catch (err) {
|
|
14124
14124
|
handleQueryError(err, finalQuery, customerId);
|
|
14125
14125
|
}
|
|
@@ -17722,12 +17722,12 @@ function skipBlanks(value, at) {
|
|
|
17722
17722
|
while (value[i] === " " || value[i] === " ") i++;
|
|
17723
17723
|
return i;
|
|
17724
17724
|
}
|
|
17725
|
-
function readQuotedField(value, open,
|
|
17725
|
+
function readQuotedField(value, open, flag2) {
|
|
17726
17726
|
let text2 = "";
|
|
17727
17727
|
let j = open + 1;
|
|
17728
17728
|
while (!(value[j] === '"' && value[j + 1] !== '"')) {
|
|
17729
17729
|
if (j >= value.length) {
|
|
17730
|
-
failWriteValidation(`--${
|
|
17730
|
+
failWriteValidation(`--${flag2} has a quote with no closing quote: ${value} \u2014 ${AD_COPY_LIST_USAGE}`);
|
|
17731
17731
|
}
|
|
17732
17732
|
text2 += value[j];
|
|
17733
17733
|
j += value[j] === '"' ? 2 : 1;
|
|
@@ -17735,18 +17735,18 @@ function readQuotedField(value, open, flag3) {
|
|
|
17735
17735
|
const after = skipBlanks(value, j + 1);
|
|
17736
17736
|
if (after < value.length && value[after] !== ",") {
|
|
17737
17737
|
failWriteValidation(
|
|
17738
|
-
`--${
|
|
17738
|
+
`--${flag2}: 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}`
|
|
17739
17739
|
);
|
|
17740
17740
|
}
|
|
17741
17741
|
return { text: text2, next: after + 1 };
|
|
17742
17742
|
}
|
|
17743
|
-
function splitQuotedList(value,
|
|
17743
|
+
function splitQuotedList(value, flag2) {
|
|
17744
17744
|
const fields = [];
|
|
17745
17745
|
let i = 0;
|
|
17746
17746
|
while (i <= value.length) {
|
|
17747
17747
|
const start = skipBlanks(value, i);
|
|
17748
17748
|
if (value[start] === '"') {
|
|
17749
|
-
const { text: text2, next } = readQuotedField(value, start,
|
|
17749
|
+
const { text: text2, next } = readQuotedField(value, start, flag2);
|
|
17750
17750
|
fields.push({ text: text2, quoted: true });
|
|
17751
17751
|
i = next;
|
|
17752
17752
|
} else {
|
|
@@ -17768,53 +17768,53 @@ function jsonStringArray(value) {
|
|
|
17768
17768
|
return void 0;
|
|
17769
17769
|
}
|
|
17770
17770
|
}
|
|
17771
|
-
function parseCopyList(value,
|
|
17771
|
+
function parseCopyList(value, flag2) {
|
|
17772
17772
|
let items;
|
|
17773
17773
|
if (Array.isArray(value)) {
|
|
17774
17774
|
items = value.filter((v) => typeof v === "string").map((v) => ({ text: v.trim(), splitAtComma: false }));
|
|
17775
17775
|
} else if (typeof value === "string") {
|
|
17776
17776
|
const trimmed = value.trim();
|
|
17777
17777
|
const json = jsonStringArray(trimmed);
|
|
17778
|
-
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, flag2);
|
|
17779
17779
|
} else {
|
|
17780
17780
|
return void 0;
|
|
17781
17781
|
}
|
|
17782
17782
|
const kept = items.filter((item) => item.text.length > 0);
|
|
17783
17783
|
return kept.length > 0 ? kept : void 0;
|
|
17784
17784
|
}
|
|
17785
|
-
function copyListFlag(value,
|
|
17786
|
-
return parseCopyList(value,
|
|
17785
|
+
function copyListFlag(value, flag2) {
|
|
17786
|
+
return parseCopyList(value, flag2)?.map((item) => item.text);
|
|
17787
17787
|
}
|
|
17788
|
-
function refuseDashLedValue(rawArgs,
|
|
17788
|
+
function refuseDashLedValue(rawArgs, flag2) {
|
|
17789
17789
|
for (let i = 0; i < rawArgs.length - 1; i++) {
|
|
17790
17790
|
if (rawArgs[i] === "--") return;
|
|
17791
17791
|
const value = rawArgs[i + 1];
|
|
17792
|
-
if (rawArgs[i] === `--${
|
|
17792
|
+
if (rawArgs[i] === `--${flag2}` && value?.startsWith("-")) {
|
|
17793
17793
|
failWriteValidation(
|
|
17794
|
-
`--${
|
|
17794
|
+
`--${flag2} 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 =: --${flag2}="${value}"`
|
|
17795
17795
|
);
|
|
17796
17796
|
}
|
|
17797
17797
|
}
|
|
17798
17798
|
}
|
|
17799
17799
|
function withRepeatedCopyFlags(args5, rawArgs) {
|
|
17800
17800
|
const out = { ...args5 };
|
|
17801
|
-
for (const
|
|
17802
|
-
refuseDashLedValue(rawArgs ?? [],
|
|
17803
|
-
const values = repeatedFlagValues(rawArgs ?? [],
|
|
17801
|
+
for (const flag2 of AD_COPY_LIST_FLAGS) {
|
|
17802
|
+
refuseDashLedValue(rawArgs ?? [], flag2);
|
|
17803
|
+
const values = repeatedFlagValues(rawArgs ?? [], flag2);
|
|
17804
17804
|
if (values.length > 1) {
|
|
17805
|
-
out[
|
|
17805
|
+
out[flag2] = values;
|
|
17806
17806
|
}
|
|
17807
17807
|
}
|
|
17808
17808
|
return out;
|
|
17809
17809
|
}
|
|
17810
17810
|
function copyListSplitHints(args5) {
|
|
17811
17811
|
const hints2 = [];
|
|
17812
|
-
for (const
|
|
17813
|
-
const items = parseCopyList(args5[
|
|
17812
|
+
for (const flag2 of AD_COPY_LIST_FLAGS) {
|
|
17813
|
+
const items = parseCopyList(args5[flag2], flag2) ?? [];
|
|
17814
17814
|
const fragments = items.filter((item, index) => index > 0 && item.splitAtComma && new RegExp("^\\p{Ll}", "u").test(item.text));
|
|
17815
17815
|
if (fragments.length > 0) {
|
|
17816
17816
|
hints2.push(
|
|
17817
|
-
`--${
|
|
17817
|
+
`--${flag2}: ${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}.`
|
|
17818
17818
|
);
|
|
17819
17819
|
}
|
|
17820
17820
|
}
|
|
@@ -18365,11 +18365,11 @@ function urlCustomParametersFromFlags(args5, rawArgs) {
|
|
|
18365
18365
|
failWriteValidation("--clear-custom-params removes every parameter \u2014 pass it OR --custom-param, not both");
|
|
18366
18366
|
}
|
|
18367
18367
|
return entries.map((entry) => {
|
|
18368
|
-
const
|
|
18369
|
-
if (
|
|
18368
|
+
const split = entry.indexOf("=");
|
|
18369
|
+
if (split <= 0) {
|
|
18370
18370
|
failWriteValidation(`--custom-param "${entry}" must be key=value (e.g. --custom-param season=summer)`);
|
|
18371
18371
|
}
|
|
18372
|
-
return { key: entry.slice(0,
|
|
18372
|
+
return { key: entry.slice(0, split), value: entry.slice(split + 1) };
|
|
18373
18373
|
});
|
|
18374
18374
|
}
|
|
18375
18375
|
var geoTargetTypeArgs = {
|
|
@@ -18382,13 +18382,13 @@ var geoTargetTypeArgs = {
|
|
|
18382
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)."
|
|
18383
18383
|
}
|
|
18384
18384
|
};
|
|
18385
|
-
function enumFlag(value,
|
|
18385
|
+
function enumFlag(value, flag2, allowed) {
|
|
18386
18386
|
if (typeof value !== "string" || value.length === 0) {
|
|
18387
18387
|
return void 0;
|
|
18388
18388
|
}
|
|
18389
18389
|
const upper2 = value.toUpperCase();
|
|
18390
18390
|
if (!allowed.includes(upper2)) {
|
|
18391
|
-
failWriteValidation(`${
|
|
18391
|
+
failWriteValidation(`${flag2} must be one of ${allowed.join(" | ")}`);
|
|
18392
18392
|
}
|
|
18393
18393
|
return upper2;
|
|
18394
18394
|
}
|
|
@@ -19108,8 +19108,8 @@ var FORMAT_CONTENT_FLAGS = {
|
|
|
19108
19108
|
// same silent drop this gate exists for, on the one format that reads no flags at all.
|
|
19109
19109
|
call: []
|
|
19110
19110
|
};
|
|
19111
|
-
function formatsReading(
|
|
19112
|
-
return Object.entries(FORMAT_CONTENT_FLAGS).filter(([, flags]) => flags.includes(
|
|
19111
|
+
function formatsReading(flag2) {
|
|
19112
|
+
return Object.entries(FORMAT_CONTENT_FLAGS).filter(([, flags]) => flags.includes(flag2)).map(([format]) => format);
|
|
19113
19113
|
}
|
|
19114
19114
|
function assertFlagsFitFormat(args5, format) {
|
|
19115
19115
|
const allowed = FORMAT_CONTENT_FLAGS[format];
|
|
@@ -19117,14 +19117,14 @@ function assertFlagsFitFormat(args5, format) {
|
|
|
19117
19117
|
return;
|
|
19118
19118
|
}
|
|
19119
19119
|
const stray = Object.keys(adContentArgs).filter(
|
|
19120
|
-
(
|
|
19120
|
+
(flag2) => flag2 !== "format" && args5[flag2] !== void 0 && !allowed.includes(flag2)
|
|
19121
19121
|
);
|
|
19122
19122
|
if (stray.length === 0) {
|
|
19123
19123
|
return;
|
|
19124
19124
|
}
|
|
19125
|
-
const detail = stray.map((
|
|
19126
|
-
const elsewhere = formatsReading(
|
|
19127
|
-
return elsewhere.length > 0 ? `--${
|
|
19125
|
+
const detail = stray.map((flag2) => {
|
|
19126
|
+
const elsewhere = formatsReading(flag2);
|
|
19127
|
+
return elsewhere.length > 0 ? `--${flag2} (${elsewhere.join(" / ")})` : `--${flag2}`;
|
|
19128
19128
|
}).join(", ");
|
|
19129
19129
|
failWriteValidation(
|
|
19130
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>"\`.`
|
|
@@ -19203,10 +19203,10 @@ var adContentArgs = {
|
|
|
19203
19203
|
"final-url": { type: "string", description: "Comma-separated final URLs" }
|
|
19204
19204
|
};
|
|
19205
19205
|
function assertNoContentFlags(args5) {
|
|
19206
|
-
const passed = Object.keys(adContentArgs).filter((
|
|
19206
|
+
const passed = Object.keys(adContentArgs).filter((flag2) => flag2 !== "format" && args5[flag2] !== void 0);
|
|
19207
19207
|
if (passed.length > 0) {
|
|
19208
19208
|
failWriteValidation(
|
|
19209
|
-
`${passed.map((
|
|
19209
|
+
`${passed.map((flag2) => `--${flag2}`).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`
|
|
19210
19210
|
);
|
|
19211
19211
|
}
|
|
19212
19212
|
}
|
|
@@ -19929,8 +19929,8 @@ function resolveAccountIdArg2(args5) {
|
|
|
19929
19929
|
function todayIso2() {
|
|
19930
19930
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
19931
19931
|
}
|
|
19932
|
-
function daysAgoIso2(
|
|
19933
|
-
return new Date(Date.now() -
|
|
19932
|
+
function daysAgoIso2(days) {
|
|
19933
|
+
return new Date(Date.now() - days * DAY_MS2).toISOString().slice(0, 10);
|
|
19934
19934
|
}
|
|
19935
19935
|
function csvOrJson2(args5) {
|
|
19936
19936
|
return args5.output ?? "json";
|
|
@@ -20004,7 +20004,7 @@ function loadPatchArg2(args5) {
|
|
|
20004
20004
|
throw err;
|
|
20005
20005
|
}
|
|
20006
20006
|
}
|
|
20007
|
-
function parseMoneyFlag(amount, currency,
|
|
20007
|
+
function parseMoneyFlag(amount, currency, flag2) {
|
|
20008
20008
|
if (amount === void 0 || amount === null || amount === "") {
|
|
20009
20009
|
return void 0;
|
|
20010
20010
|
}
|
|
@@ -20012,11 +20012,11 @@ function parseMoneyFlag(amount, currency, flag3) {
|
|
|
20012
20012
|
return { amount: String(amount) };
|
|
20013
20013
|
}
|
|
20014
20014
|
if (typeof currency !== "string" || currency.length !== 3) {
|
|
20015
|
-
failWriteValidation2(`${
|
|
20015
|
+
failWriteValidation2(`${flag2} got an invalid --currency (expected a 3-letter code like EUR)`);
|
|
20016
20016
|
}
|
|
20017
20017
|
return { amount: String(amount), currencyCode: currency.toUpperCase() };
|
|
20018
20018
|
}
|
|
20019
|
-
function parseDateFlag(value,
|
|
20019
|
+
function parseDateFlag(value, flag2) {
|
|
20020
20020
|
if (value === void 0 || value === null || value === "") {
|
|
20021
20021
|
return void 0;
|
|
20022
20022
|
}
|
|
@@ -20026,11 +20026,11 @@ function parseDateFlag(value, flag3) {
|
|
|
20026
20026
|
}
|
|
20027
20027
|
const parsed = Date.parse(raw);
|
|
20028
20028
|
if (Number.isNaN(parsed)) {
|
|
20029
|
-
failWriteValidation2(`${
|
|
20029
|
+
failWriteValidation2(`${flag2} must be an ISO date (2026-07-10) or epoch milliseconds`);
|
|
20030
20030
|
}
|
|
20031
20031
|
return parsed;
|
|
20032
20032
|
}
|
|
20033
|
-
function parseOnOffFlag(value,
|
|
20033
|
+
function parseOnOffFlag(value, flag2) {
|
|
20034
20034
|
if (value === void 0 || value === null || value === "") {
|
|
20035
20035
|
return void 0;
|
|
20036
20036
|
}
|
|
@@ -20041,7 +20041,7 @@ function parseOnOffFlag(value, flag3) {
|
|
|
20041
20041
|
if (raw === "off" || raw === "false") {
|
|
20042
20042
|
return false;
|
|
20043
20043
|
}
|
|
20044
|
-
failWriteValidation2(`${
|
|
20044
|
+
failWriteValidation2(`${flag2} must be on|off`);
|
|
20045
20045
|
}
|
|
20046
20046
|
function parseLocaleFlag(value) {
|
|
20047
20047
|
if (value === void 0 || value === null || value === "") {
|
|
@@ -21227,13 +21227,13 @@ Examples:
|
|
|
21227
21227
|
}
|
|
21228
21228
|
});
|
|
21229
21229
|
}
|
|
21230
|
-
function trackingPairs(value,
|
|
21230
|
+
function trackingPairs(value, flag2) {
|
|
21231
21231
|
const raw = value === void 0 ? [] : Array.isArray(value) ? value : [value];
|
|
21232
21232
|
return raw.flatMap(
|
|
21233
21233
|
(entry) => String(entry).split("&").filter((pair) => pair.length > 0).map((pair) => {
|
|
21234
21234
|
const at = pair.indexOf("=");
|
|
21235
21235
|
if (at < 1 || at === pair.length - 1) {
|
|
21236
|
-
failWriteValidation2(`${
|
|
21236
|
+
failWriteValidation2(`${flag2} expects key=value pairs \u2014 got "${pair}"`);
|
|
21237
21237
|
}
|
|
21238
21238
|
return [pair.slice(0, at).trim(), pair.slice(at + 1).trim()];
|
|
21239
21239
|
})
|
|
@@ -21569,9 +21569,9 @@ var CREATIVE_AMEND_CONTENT_FLAGS = [
|
|
|
21569
21569
|
];
|
|
21570
21570
|
function creativeContentPatch(args5) {
|
|
21571
21571
|
const patch = {};
|
|
21572
|
-
for (const [
|
|
21573
|
-
if (args5[
|
|
21574
|
-
patch[key] = args5[
|
|
21572
|
+
for (const [flag2, key] of CREATIVE_AMEND_CONTENT_FLAGS) {
|
|
21573
|
+
if (args5[flag2] !== void 0) {
|
|
21574
|
+
patch[key] = args5[flag2];
|
|
21575
21575
|
}
|
|
21576
21576
|
}
|
|
21577
21577
|
if (args5.cta !== void 0) {
|
|
@@ -22226,11 +22226,11 @@ function resolveDateRange(args5) {
|
|
|
22226
22226
|
return { start, end };
|
|
22227
22227
|
}
|
|
22228
22228
|
const lastDaysRaw = args5["last-days"];
|
|
22229
|
-
const
|
|
22230
|
-
if (!Number.isFinite(
|
|
22229
|
+
const days = lastDaysRaw ? Number(lastDaysRaw) : 7;
|
|
22230
|
+
if (!Number.isFinite(days) || days < 1 || days > 730) {
|
|
22231
22231
|
handleLinkedinError(new Error(`Invalid --last-days "${lastDaysRaw}". Use a positive number \u2264 730.`));
|
|
22232
22232
|
}
|
|
22233
|
-
return { start: daysAgoIso2(
|
|
22233
|
+
return { start: daysAgoIso2(days), end: todayIso2() };
|
|
22234
22234
|
}
|
|
22235
22235
|
function resolveScopeIds(args5, level) {
|
|
22236
22236
|
if (level === "account") {
|
|
@@ -22358,7 +22358,7 @@ Examples \u2014 common AI questions:
|
|
|
22358
22358
|
}
|
|
22359
22359
|
const range = resolveDateRange(args5);
|
|
22360
22360
|
const metrics = commaSplit(args5.metrics);
|
|
22361
|
-
const
|
|
22361
|
+
const limit = args5.limit ? Number(args5.limit) : 1e3;
|
|
22362
22362
|
const request = {
|
|
22363
22363
|
level,
|
|
22364
22364
|
ids,
|
|
@@ -22368,7 +22368,7 @@ Examples \u2014 common AI questions:
|
|
|
22368
22368
|
start: range.start,
|
|
22369
22369
|
end: range.end,
|
|
22370
22370
|
granularity,
|
|
22371
|
-
limit
|
|
22371
|
+
limit
|
|
22372
22372
|
};
|
|
22373
22373
|
try {
|
|
22374
22374
|
const data = await apiPost("/api/ads/linkedin/analytics", {
|
|
@@ -23160,8 +23160,8 @@ function numberOf2(v) {
|
|
|
23160
23160
|
}
|
|
23161
23161
|
return 0;
|
|
23162
23162
|
}
|
|
23163
|
-
function topByImpressions(rows,
|
|
23164
|
-
return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0,
|
|
23163
|
+
function topByImpressions(rows, limit) {
|
|
23164
|
+
return [...rows].sort((a, b) => numberOf2(b.impressions) - numberOf2(a.impressions)).slice(0, limit);
|
|
23165
23165
|
}
|
|
23166
23166
|
var demographicsCommand = defineCommand45({
|
|
23167
23167
|
meta: {
|
|
@@ -23252,11 +23252,11 @@ function resolveRange(args5) {
|
|
|
23252
23252
|
if (start) {
|
|
23253
23253
|
return { start, end };
|
|
23254
23254
|
}
|
|
23255
|
-
const
|
|
23256
|
-
if (!Number.isFinite(
|
|
23255
|
+
const days = args5["last-days"] ? Number(args5["last-days"]) : 30;
|
|
23256
|
+
if (!Number.isFinite(days) || days < 1) {
|
|
23257
23257
|
handleLinkedinError(new Error("Invalid --last-days; must be a positive integer."));
|
|
23258
23258
|
}
|
|
23259
|
-
return { start: daysAgoIso2(
|
|
23259
|
+
return { start: daysAgoIso2(days), end: todayIso2() };
|
|
23260
23260
|
}
|
|
23261
23261
|
|
|
23262
23262
|
// src/commands/ads/linkedin/draft.ts
|
|
@@ -25842,7 +25842,7 @@ function mergePayload3(file, flags) {
|
|
|
25842
25842
|
}
|
|
25843
25843
|
return merged;
|
|
25844
25844
|
}
|
|
25845
|
-
function parseMoneyFlag2(amount, currency,
|
|
25845
|
+
function parseMoneyFlag2(amount, currency, flag2) {
|
|
25846
25846
|
if (amount === void 0 || amount === null || amount === "") {
|
|
25847
25847
|
return void 0;
|
|
25848
25848
|
}
|
|
@@ -25850,11 +25850,11 @@ function parseMoneyFlag2(amount, currency, flag3) {
|
|
|
25850
25850
|
return { amount: String(amount) };
|
|
25851
25851
|
}
|
|
25852
25852
|
if (typeof currency !== "string" || currency.length !== 3) {
|
|
25853
|
-
failWriteValidation3(`${
|
|
25853
|
+
failWriteValidation3(`${flag2} got an invalid --currency (expected a 3-letter code like USD)`);
|
|
25854
25854
|
}
|
|
25855
25855
|
return { amount: String(amount), currencyCode: currency.toUpperCase() };
|
|
25856
25856
|
}
|
|
25857
|
-
function parseDateFlag2(value,
|
|
25857
|
+
function parseDateFlag2(value, flag2) {
|
|
25858
25858
|
if (value === void 0 || value === null || value === "") {
|
|
25859
25859
|
return void 0;
|
|
25860
25860
|
}
|
|
@@ -25864,7 +25864,7 @@ function parseDateFlag2(value, flag3) {
|
|
|
25864
25864
|
}
|
|
25865
25865
|
const parsed = Date.parse(raw);
|
|
25866
25866
|
if (Number.isNaN(parsed)) {
|
|
25867
|
-
failWriteValidation3(`${
|
|
25867
|
+
failWriteValidation3(`${flag2} must be an ISO date (2026-07-10) or epoch milliseconds`);
|
|
25868
25868
|
}
|
|
25869
25869
|
return parsed;
|
|
25870
25870
|
}
|
|
@@ -25878,13 +25878,13 @@ function listFlag2(value) {
|
|
|
25878
25878
|
function upper(value) {
|
|
25879
25879
|
return typeof value === "string" && value.length > 0 ? value.toUpperCase() : void 0;
|
|
25880
25880
|
}
|
|
25881
|
-
function numberFlag(value,
|
|
25881
|
+
function numberFlag(value, flag2) {
|
|
25882
25882
|
if (value === void 0 || value === null || value === "") {
|
|
25883
25883
|
return void 0;
|
|
25884
25884
|
}
|
|
25885
25885
|
const n = Number(value);
|
|
25886
25886
|
if (!Number.isFinite(n)) {
|
|
25887
|
-
failWriteValidation3(`${
|
|
25887
|
+
failWriteValidation3(`${flag2} must be a number`);
|
|
25888
25888
|
}
|
|
25889
25889
|
return n;
|
|
25890
25890
|
}
|
|
@@ -27313,8 +27313,8 @@ function shouldAutoAsync(body) {
|
|
|
27313
27313
|
return true;
|
|
27314
27314
|
}
|
|
27315
27315
|
if (body.since && body.until) {
|
|
27316
|
-
const
|
|
27317
|
-
if (
|
|
27316
|
+
const days = (Date.parse(body.until) - Date.parse(body.since)) / 864e5;
|
|
27317
|
+
if (days > 90) {
|
|
27318
27318
|
return true;
|
|
27319
27319
|
}
|
|
27320
27320
|
}
|
|
@@ -27783,14 +27783,14 @@ async function runStats(args5) {
|
|
|
27783
27783
|
if (!pixelId) {
|
|
27784
27784
|
handleMetaError(new Error("--pixel-id is required when --stats is set"));
|
|
27785
27785
|
}
|
|
27786
|
-
const
|
|
27787
|
-
if (!Number.isInteger(
|
|
27786
|
+
const days = args5.days ? Number(args5.days) : 7;
|
|
27787
|
+
if (!Number.isInteger(days) || days <= 0 || days > 90) {
|
|
27788
27788
|
handleMetaError(new Error("--days must be a positive integer \u2264 90"));
|
|
27789
27789
|
}
|
|
27790
27790
|
const params2 = {
|
|
27791
27791
|
"pixel-id": pixelId,
|
|
27792
27792
|
aggregation: args5.aggregation ?? "event",
|
|
27793
|
-
"start-time": daysAgoIso(
|
|
27793
|
+
"start-time": daysAgoIso(days),
|
|
27794
27794
|
"end-time": todayIso()
|
|
27795
27795
|
};
|
|
27796
27796
|
if (args5["no-cache"]) params2["skip-cache"] = "true";
|
|
@@ -28450,10 +28450,10 @@ function parseXMoney(value) {
|
|
|
28450
28450
|
}
|
|
28451
28451
|
return { ok: true, micros: Math.round(amount * 1e6) };
|
|
28452
28452
|
}
|
|
28453
|
-
function microsFromArg(value,
|
|
28453
|
+
function microsFromArg(value, flag2) {
|
|
28454
28454
|
const parsed = parseXMoney(value);
|
|
28455
28455
|
if (!parsed.ok) {
|
|
28456
|
-
failWriteValidation4(`${
|
|
28456
|
+
failWriteValidation4(`${flag2} ${parsed.reason}`);
|
|
28457
28457
|
}
|
|
28458
28458
|
return parsed.micros;
|
|
28459
28459
|
}
|
|
@@ -30237,14 +30237,14 @@ function resolveQueryFromArgs(args5, timeZone) {
|
|
|
30237
30237
|
granularity = args5.granularity ?? preset.granularity;
|
|
30238
30238
|
placement = args5.placement ?? preset.placement;
|
|
30239
30239
|
const requested = args5.days ? Number(args5.days) : preset.defaultDays;
|
|
30240
|
-
const
|
|
30240
|
+
const days = Math.min(SYNC_MAX_DAYS, Math.max(1, requested));
|
|
30241
30241
|
if (requested > SYNC_MAX_DAYS) {
|
|
30242
30242
|
hints2.push(
|
|
30243
|
-
`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 ${days}. 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>`
|
|
30244
30244
|
);
|
|
30245
30245
|
}
|
|
30246
30246
|
const floor = granularity === "DAY" ? (d) => accountMidnightIso(d, timeZone) : isoHourFloor;
|
|
30247
|
-
startTime ??= floor(
|
|
30247
|
+
startTime ??= floor(days);
|
|
30248
30248
|
endTime ??= floor(0);
|
|
30249
30249
|
}
|
|
30250
30250
|
const entityIds = parseCsv5(args5["entity-ids"]);
|
|
@@ -31549,32 +31549,32 @@ function isUsableStepNameKey(key) {
|
|
|
31549
31549
|
// src/commands/analytics/conversionArgs.ts
|
|
31550
31550
|
var ConversionArgsError = class extends Error {
|
|
31551
31551
|
};
|
|
31552
|
-
function allValues(
|
|
31552
|
+
function allValues(flag2, argv) {
|
|
31553
31553
|
const values = [];
|
|
31554
31554
|
for (let i = 0; i < argv.length; i += 1) {
|
|
31555
31555
|
const arg = argv[i];
|
|
31556
|
-
if (arg ===
|
|
31556
|
+
if (arg === flag2) {
|
|
31557
31557
|
const next = argv[i + 1];
|
|
31558
31558
|
if (next !== void 0 && !next.startsWith("--")) values.push(next);
|
|
31559
31559
|
continue;
|
|
31560
31560
|
}
|
|
31561
|
-
if (arg.startsWith(`${
|
|
31561
|
+
if (arg.startsWith(`${flag2}=`)) values.push(arg.slice(flag2.length + 1));
|
|
31562
31562
|
}
|
|
31563
31563
|
return values.map((value) => value.trim()).filter((value) => value !== "");
|
|
31564
31564
|
}
|
|
31565
|
-
function onlyOnce(value,
|
|
31565
|
+
function onlyOnce(value, flag2, argv) {
|
|
31566
31566
|
if (value === void 0) return void 0;
|
|
31567
|
-
const given = argv.filter((arg) => arg ===
|
|
31567
|
+
const given = argv.filter((arg) => arg === flag2 || arg.startsWith(`${flag2}=`)).length;
|
|
31568
31568
|
if (given > 1) {
|
|
31569
31569
|
throw new ConversionArgsError(
|
|
31570
|
-
`${
|
|
31570
|
+
`${flag2} was given ${given} times and only the last would have been used. It takes one value.`
|
|
31571
31571
|
);
|
|
31572
31572
|
}
|
|
31573
31573
|
const trimmed = String(value).trim();
|
|
31574
31574
|
return trimmed === "" ? void 0 : trimmed;
|
|
31575
31575
|
}
|
|
31576
|
-
function repeatable(
|
|
31577
|
-
const fromArgv = allValues(
|
|
31576
|
+
function repeatable(flag2, cittyValue, argv) {
|
|
31577
|
+
const fromArgv = allValues(flag2, argv);
|
|
31578
31578
|
if (fromArgv.length > 0) return fromArgv;
|
|
31579
31579
|
if (cittyValue === void 0) return [];
|
|
31580
31580
|
const trimmed = String(cittyValue).trim();
|
|
@@ -31614,11 +31614,11 @@ function checkEventKeys(eventKeys) {
|
|
|
31614
31614
|
}
|
|
31615
31615
|
function readDays(raw) {
|
|
31616
31616
|
if (raw === void 0) return void 0;
|
|
31617
|
-
const
|
|
31618
|
-
if (!Number.isFinite(
|
|
31617
|
+
const days = Number(raw);
|
|
31618
|
+
if (!Number.isFinite(days) || days <= 0) {
|
|
31619
31619
|
throw new ConversionArgsError("--days must be a positive number of days.");
|
|
31620
31620
|
}
|
|
31621
|
-
return
|
|
31621
|
+
return days;
|
|
31622
31622
|
}
|
|
31623
31623
|
function parseConversionsArgs(raw, argv) {
|
|
31624
31624
|
const countMode = onlyOnce(raw["count-mode"], "--count-mode", argv);
|
|
@@ -32564,8 +32564,8 @@ var SET_FLAGS = ["--source-event", "--platform", "--tag", "--event"];
|
|
|
32564
32564
|
function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
32565
32565
|
const set = parseSetFlags(raw, argv, now);
|
|
32566
32566
|
const remove = onlyOnce(raw.remove, "--remove", argv);
|
|
32567
|
-
const
|
|
32568
|
-
if (
|
|
32567
|
+
const days = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
32568
|
+
if (days !== void 0 && (!Number.isInteger(days) || days <= 0 || days > 400)) {
|
|
32569
32569
|
throw new ConversionArgsError("--days must be a whole number of days, from 1 to 400.");
|
|
32570
32570
|
}
|
|
32571
32571
|
const uploads = onlyOnce(raw.uploads, "--uploads", argv);
|
|
@@ -32580,17 +32580,17 @@ function parseSendsArgs(raw, argv, now = Date.now()) {
|
|
|
32580
32580
|
return {
|
|
32581
32581
|
...set === void 0 ? {} : { set },
|
|
32582
32582
|
...remove === void 0 ? {} : { remove },
|
|
32583
|
-
...
|
|
32583
|
+
...days === void 0 ? {} : { days },
|
|
32584
32584
|
...uploads === void 0 ? {} : { uploads },
|
|
32585
32585
|
...raw.failed === true ? { failedOnly: true } : {},
|
|
32586
32586
|
...raw.skipped === true ? { skippedOnly: true } : {},
|
|
32587
32587
|
full: raw.full === true
|
|
32588
32588
|
};
|
|
32589
32589
|
}
|
|
32590
|
-
function flagValueAt(argv,
|
|
32590
|
+
function flagValueAt(argv, flag2, index) {
|
|
32591
32591
|
const arg = argv[index] ?? "";
|
|
32592
|
-
if (arg ===
|
|
32593
|
-
return arg.startsWith(`${
|
|
32592
|
+
if (arg === flag2) return argv[index + 1];
|
|
32593
|
+
return arg.startsWith(`${flag2}=`) ? arg.slice(flag2.length + 1) : void 0;
|
|
32594
32594
|
}
|
|
32595
32595
|
function parseParameterArgs(argv) {
|
|
32596
32596
|
const parameters = {};
|
|
@@ -32621,7 +32621,7 @@ function parseSetFlags(raw, argv, now) {
|
|
|
32621
32621
|
"--tag": onlyOnce(raw.tag, "--tag", argv),
|
|
32622
32622
|
"--event": onlyOnce(raw.event, "--event", argv)
|
|
32623
32623
|
};
|
|
32624
|
-
const given = SET_FLAGS.filter((
|
|
32624
|
+
const given = SET_FLAGS.filter((flag2) => values[flag2] !== void 0);
|
|
32625
32625
|
const set = raw.set === true;
|
|
32626
32626
|
if (!set) {
|
|
32627
32627
|
if (given.length > 0) {
|
|
@@ -32631,7 +32631,7 @@ function parseSetFlags(raw, argv, now) {
|
|
|
32631
32631
|
}
|
|
32632
32632
|
return void 0;
|
|
32633
32633
|
}
|
|
32634
|
-
const missing = SET_FLAGS.filter((
|
|
32634
|
+
const missing = SET_FLAGS.filter((flag2) => values[flag2] === void 0);
|
|
32635
32635
|
if (missing.length > 0) {
|
|
32636
32636
|
throw new ConversionArgsError(
|
|
32637
32637
|
`--set needs ${SET_FLAGS.join(", ")}; missing ${missing.join(", ")}. Copy --tag from platforms[].tags of a plain \`baker analytics sends\`, never from memory.`
|
|
@@ -33286,15 +33286,15 @@ registerSchema({
|
|
|
33286
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",
|
|
33287
33287
|
args: args3
|
|
33288
33288
|
});
|
|
33289
|
-
function flagValueAt2(argv,
|
|
33289
|
+
function flagValueAt2(argv, flag2, index) {
|
|
33290
33290
|
const arg = argv[index] ?? "";
|
|
33291
|
-
if (arg ===
|
|
33292
|
-
return arg.startsWith(`${
|
|
33291
|
+
if (arg === flag2) return argv[index + 1];
|
|
33292
|
+
return arg.startsWith(`${flag2}=`) ? arg.slice(flag2.length + 1) : void 0;
|
|
33293
33293
|
}
|
|
33294
|
-
function parseRepeated(argv,
|
|
33294
|
+
function parseRepeated(argv, flag2) {
|
|
33295
33295
|
const values = [];
|
|
33296
33296
|
for (let index = 0; index < argv.length; index += 1) {
|
|
33297
|
-
const value = flagValueAt2(argv,
|
|
33297
|
+
const value = flagValueAt2(argv, flag2, index);
|
|
33298
33298
|
if (value !== void 0) values.push(value);
|
|
33299
33299
|
}
|
|
33300
33300
|
return values;
|
|
@@ -34178,10 +34178,10 @@ Examples:
|
|
|
34178
34178
|
});
|
|
34179
34179
|
process.exit(1);
|
|
34180
34180
|
}
|
|
34181
|
-
const
|
|
34181
|
+
const days = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
34182
34182
|
const response = await apiPost("/api/analytics/tracking", {
|
|
34183
34183
|
...platform ? { platform } : {},
|
|
34184
|
-
...
|
|
34184
|
+
...days !== void 0 && Number.isFinite(days) ? { days } : {}
|
|
34185
34185
|
});
|
|
34186
34186
|
writeJsonEnvelope(response);
|
|
34187
34187
|
} catch (err) {
|
|
@@ -34412,12 +34412,12 @@ Examples:
|
|
|
34412
34412
|
args: args5,
|
|
34413
34413
|
run: async ({ args: raw }) => {
|
|
34414
34414
|
try {
|
|
34415
|
-
const
|
|
34415
|
+
const limit = raw.limit === void 0 ? void 0 : Number(raw.limit);
|
|
34416
34416
|
const response = await apiPost("/api/analytics/arrivals", {
|
|
34417
34417
|
...raw.mode ? { mode: String(raw.mode) } : {},
|
|
34418
34418
|
...raw.outcome ? { outcome: String(raw.outcome) } : {},
|
|
34419
34419
|
...raw.event ? { eventName: String(raw.event) } : {},
|
|
34420
|
-
...
|
|
34420
|
+
...limit !== void 0 && Number.isFinite(limit) ? { limit } : {},
|
|
34421
34421
|
...raw.full ? { full: true } : {}
|
|
34422
34422
|
});
|
|
34423
34423
|
writeJsonEnvelope(response);
|
|
@@ -34869,8 +34869,8 @@ function parseGuardrails(value) {
|
|
|
34869
34869
|
}
|
|
34870
34870
|
function buildProfilePatch(args5) {
|
|
34871
34871
|
const patch = {};
|
|
34872
|
-
for (const [
|
|
34873
|
-
const value = args5[
|
|
34872
|
+
for (const [flag2, field] of TEXT_FIELDS) {
|
|
34873
|
+
const value = args5[flag2];
|
|
34874
34874
|
if (typeof value === "string") {
|
|
34875
34875
|
Object.assign(patch, { [field]: value.trim() });
|
|
34876
34876
|
}
|
|
@@ -35726,7 +35726,7 @@ function undisambiguatedSubsets(faces) {
|
|
|
35726
35726
|
if (new Set(faces.map((face) => face.subset)).size < 2) return [];
|
|
35727
35727
|
return [...new Set(faces.filter((face) => !face.unicodeRange).map((face) => face.subset))];
|
|
35728
35728
|
}
|
|
35729
|
-
function suggestFamilies(wanted, catalogue,
|
|
35729
|
+
function suggestFamilies(wanted, catalogue, limit = 5) {
|
|
35730
35730
|
const key = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
35731
35731
|
const target2 = key(wanted);
|
|
35732
35732
|
if (!target2) return [];
|
|
@@ -35739,7 +35739,7 @@ function suggestFamilies(wanted, catalogue, limit2 = 5) {
|
|
|
35739
35739
|
const shared = words2.filter((w) => w.length > 2 && candidate.includes(w)).length;
|
|
35740
35740
|
return { family, score: shared > 0 ? 3 + (words2.length - shared) : Number.POSITIVE_INFINITY };
|
|
35741
35741
|
}).filter((c) => Number.isFinite(c.score)).sort((a, b) => a.score - b.score || a.family.localeCompare(b.family));
|
|
35742
|
-
return scored.slice(0,
|
|
35742
|
+
return scored.slice(0, limit).map((c) => c.family);
|
|
35743
35743
|
}
|
|
35744
35744
|
function asFontsourceMeta(body) {
|
|
35745
35745
|
if (typeof body !== "object" || body === null) return null;
|
|
@@ -35876,16 +35876,16 @@ function googleFontRequests(css) {
|
|
|
35876
35876
|
}
|
|
35877
35877
|
return out;
|
|
35878
35878
|
}
|
|
35879
|
-
function resolveFetchWeights(
|
|
35880
|
-
if (
|
|
35881
|
-
return String(
|
|
35879
|
+
function resolveFetchWeights(flag2, declared) {
|
|
35880
|
+
if (flag2) {
|
|
35881
|
+
return String(flag2).split(",").map((w) => Number(w.trim())).filter((w) => Number.isInteger(w) && w >= 100 && w <= 900);
|
|
35882
35882
|
}
|
|
35883
35883
|
return declared?.length ? declared : [400];
|
|
35884
35884
|
}
|
|
35885
35885
|
var DEFAULT_SUBSETS = ["latin"];
|
|
35886
|
-
function resolveFetchSubsets(
|
|
35887
|
-
const asked = String(
|
|
35888
|
-
const named =
|
|
35886
|
+
function resolveFetchSubsets(flag2, selfHosted) {
|
|
35887
|
+
const asked = String(flag2 ?? "").split(",").map((subset) => subset.trim()).filter(Boolean);
|
|
35888
|
+
const named = flag2 ? [...new Set(asked)] : selfHosted;
|
|
35889
35889
|
return named.length > 0 ? named : [...DEFAULT_SUBSETS];
|
|
35890
35890
|
}
|
|
35891
35891
|
function resolveFetchStyles(italic, selfHosted) {
|
|
@@ -41631,11 +41631,11 @@ function classifyAudio(volumedetect, hasAudioStream) {
|
|
|
41631
41631
|
}
|
|
41632
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.";
|
|
41633
41633
|
var REVIEW_CONCURRENCY = 3;
|
|
41634
|
-
async function mapWithLimit(items,
|
|
41634
|
+
async function mapWithLimit(items, limit, fn) {
|
|
41635
41635
|
const out = new Array(items.length);
|
|
41636
41636
|
let next = 0;
|
|
41637
41637
|
await Promise.all(
|
|
41638
|
-
Array.from({ length: Math.min(
|
|
41638
|
+
Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
41639
41639
|
for (let i = next++; i < items.length; i = next++) {
|
|
41640
41640
|
out[i] = await fn(items[i]);
|
|
41641
41641
|
}
|
|
@@ -42958,8 +42958,8 @@ async function resolveCastAvatar(handle) {
|
|
|
42958
42958
|
};
|
|
42959
42959
|
}
|
|
42960
42960
|
}
|
|
42961
|
-
async function resolveCastAvatars(
|
|
42962
|
-
const handles = String(
|
|
42961
|
+
async function resolveCastAvatars(flag2) {
|
|
42962
|
+
const handles = String(flag2 ?? "").split(",").map((h) => h.trim()).filter(Boolean);
|
|
42963
42963
|
const avatars = [];
|
|
42964
42964
|
for (const handle of handles) {
|
|
42965
42965
|
const resolved = await resolveCastAvatar(handle);
|
|
@@ -43072,7 +43072,7 @@ function fail3(code, message) {
|
|
|
43072
43072
|
process.exit(2);
|
|
43073
43073
|
}
|
|
43074
43074
|
function resolveModels(args5) {
|
|
43075
|
-
const pick = (
|
|
43075
|
+
const pick = (flag2, kind, fallback) => args5[flag2] ? String(args5[flag2]) : resolveModel(kind, fallback);
|
|
43076
43076
|
return {
|
|
43077
43077
|
describeModel: pick("describe-model", "image_describe", "~google/gemini-pro-latest"),
|
|
43078
43078
|
selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
|
|
@@ -43090,13 +43090,13 @@ var PLATFORM_PLACEMENTS = {
|
|
|
43090
43090
|
other: void 0
|
|
43091
43091
|
};
|
|
43092
43092
|
function resolvePlacements(placementsFlag, definitionPlatform) {
|
|
43093
|
-
const
|
|
43094
|
-
if (
|
|
43095
|
-
if (
|
|
43096
|
-
if (AD_FORMAT_PLATFORMS.includes(
|
|
43093
|
+
const flag2 = placementsFlag?.trim();
|
|
43094
|
+
if (flag2 === void 0 || flag2 === "") return { ok: true, placements: PLATFORM_PLACEMENTS[definitionPlatform] };
|
|
43095
|
+
if (flag2 === "none") return { ok: true, placements: void 0 };
|
|
43096
|
+
if (AD_FORMAT_PLATFORMS.includes(flag2)) return { ok: true, placements: flag2 };
|
|
43097
43097
|
return {
|
|
43098
43098
|
ok: false,
|
|
43099
|
-
message: `--placements "${
|
|
43099
|
+
message: `--placements "${flag2}" is not a valid placement set. Use one of: ${AD_FORMAT_PLATFORMS.join(", ")}, or "none" for a single base ad.`
|
|
43100
43100
|
};
|
|
43101
43101
|
}
|
|
43102
43102
|
function regionCount(layout) {
|
|
@@ -45111,7 +45111,7 @@ function parseBudget(raw) {
|
|
|
45111
45111
|
throw new Error(`--budget must be one of ${VIDEO_BUDGETS.join(", ")} (got "${v}")`);
|
|
45112
45112
|
}
|
|
45113
45113
|
function resolveModels2(args5) {
|
|
45114
|
-
const pick = (
|
|
45114
|
+
const pick = (flag2, kind, fallback) => args5[flag2] ? String(args5[flag2]) : resolveModel2(kind, fallback);
|
|
45115
45115
|
return {
|
|
45116
45116
|
// Flash by default: ~2-3× faster per call than Pro, which keeps each
|
|
45117
45117
|
// per-scene deconstruct step well inside the action time budget and turns a
|
|
@@ -45886,9 +45886,9 @@ var listCommand13 = defineCommand121({
|
|
|
45886
45886
|
}
|
|
45887
45887
|
body.status = args5.status;
|
|
45888
45888
|
}
|
|
45889
|
-
const
|
|
45890
|
-
if (
|
|
45891
|
-
body.limit =
|
|
45889
|
+
const limit = parseBoundedInt(args5.limit, "limit", 1, 100);
|
|
45890
|
+
if (limit !== void 0) {
|
|
45891
|
+
body.limit = limit;
|
|
45892
45892
|
}
|
|
45893
45893
|
if (args5.full) {
|
|
45894
45894
|
body.full = true;
|
|
@@ -45985,9 +45985,9 @@ var transcriptCommand = defineCommand121({
|
|
|
45985
45985
|
run: async ({ args: args5 }) => {
|
|
45986
45986
|
try {
|
|
45987
45987
|
const body = { chatId: args5.id };
|
|
45988
|
-
const
|
|
45989
|
-
if (
|
|
45990
|
-
body.limit =
|
|
45988
|
+
const limit = parseBoundedInt(args5.limit, "limit", 1, 1e3);
|
|
45989
|
+
if (limit !== void 0) {
|
|
45990
|
+
body.limit = limit;
|
|
45991
45991
|
}
|
|
45992
45992
|
if (args5.full) {
|
|
45993
45993
|
body.full = true;
|
|
@@ -46786,12 +46786,12 @@ function count(value, unit) {
|
|
|
46786
46786
|
return `about ${value} ${unit}${value === 1 ? "" : "s"}`;
|
|
46787
46787
|
}
|
|
46788
46788
|
function describeWait(earliestDecisionAt, now) {
|
|
46789
|
-
const
|
|
46790
|
-
if (
|
|
46791
|
-
if (
|
|
46792
|
-
if (
|
|
46793
|
-
if (
|
|
46794
|
-
return count(Math.round(
|
|
46789
|
+
const days = (earliestDecisionAt - now) / DAY_MS5;
|
|
46790
|
+
if (days <= 0) return "any moment now";
|
|
46791
|
+
if (days < 1) return "within a day";
|
|
46792
|
+
if (days < 14) return count(Math.round(days), "day");
|
|
46793
|
+
if (days < 60) return count(Math.round(days / 7), "week");
|
|
46794
|
+
return count(Math.round(days / 30), "month");
|
|
46795
46795
|
}
|
|
46796
46796
|
function roughCount(count2) {
|
|
46797
46797
|
if (count2 < 10) return `about ${Math.max(1, Math.round(count2)).toLocaleString("en-US")}`;
|
|
@@ -47933,12 +47933,12 @@ var historyCommand = defineCommand124({
|
|
|
47933
47933
|
limit: { type: "string", description: "At most this many, newest first", required: false }
|
|
47934
47934
|
},
|
|
47935
47935
|
run: async ({ args: args5 }) => {
|
|
47936
|
-
const
|
|
47937
|
-
if (
|
|
47936
|
+
const limit = args5.limit === void 0 ? void 0 : Number(args5.limit);
|
|
47937
|
+
if (limit !== void 0 && !(Number.isInteger(limit) && limit > 0)) fail5("`--limit` is a whole number above zero");
|
|
47938
47938
|
try {
|
|
47939
47939
|
const response = await apiPost("/api/experiments/history", {
|
|
47940
47940
|
...args5.landing ? { landingSlug: String(args5.landing) } : {},
|
|
47941
|
-
...
|
|
47941
|
+
...limit === void 0 ? {} : { limit }
|
|
47942
47942
|
});
|
|
47943
47943
|
writeJsonEnvelope({
|
|
47944
47944
|
ok: true,
|
|
@@ -50419,8 +50419,8 @@ function parseFunnelArgs(raw) {
|
|
|
50419
50419
|
"Give one of --steps, --step, --remove-step, --preset, --add-trigger or --remove-trigger, not two."
|
|
50420
50420
|
);
|
|
50421
50421
|
}
|
|
50422
|
-
const
|
|
50423
|
-
if (
|
|
50422
|
+
const days = raw.days === void 0 ? void 0 : Number(raw.days);
|
|
50423
|
+
if (days !== void 0 && (!Number.isInteger(days) || days <= 0 || days > 400)) {
|
|
50424
50424
|
throw new FunnelArgsError("--days must be a whole number of days, from 1 to 400.");
|
|
50425
50425
|
}
|
|
50426
50426
|
return {
|
|
@@ -50432,7 +50432,7 @@ function parseFunnelArgs(raw) {
|
|
|
50432
50432
|
...removeTrigger === void 0 ? {} : { removeTrigger },
|
|
50433
50433
|
templates: raw.templates === true,
|
|
50434
50434
|
moments: raw.moments === true,
|
|
50435
|
-
...
|
|
50435
|
+
...days === void 0 ? {} : { days }
|
|
50436
50436
|
};
|
|
50437
50437
|
}
|
|
50438
50438
|
function funnelWrite(args5) {
|
|
@@ -50552,19 +50552,19 @@ function parsePreset(raw) {
|
|
|
50552
50552
|
}
|
|
50553
50553
|
return raw;
|
|
50554
50554
|
}
|
|
50555
|
-
function parseWayIn(stepKey, eventKey,
|
|
50555
|
+
function parseWayIn(stepKey, eventKey, flag2) {
|
|
50556
50556
|
if (stepKey === void 0) return void 0;
|
|
50557
50557
|
if (typeof stepKey !== "string" || stepKey.trim() === "") {
|
|
50558
|
-
throw new FunnelArgsError(`${
|
|
50558
|
+
throw new FunnelArgsError(`${flag2} takes the key of the step to change: \`${flag2} lead\`.`);
|
|
50559
50559
|
}
|
|
50560
50560
|
if (typeof eventKey !== "string" || eventKey.trim() === "") {
|
|
50561
|
-
throw new FunnelArgsError(`${
|
|
50561
|
+
throw new FunnelArgsError(`${flag2} needs --event, naming what gets somebody there.`, {
|
|
50562
50562
|
action: "read_the_moments",
|
|
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: \`${
|
|
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: \`${flag2} ${stepKey.trim()} --event "<key>"\`.`
|
|
50564
50564
|
});
|
|
50565
50565
|
}
|
|
50566
50566
|
const key = eventKey.trim();
|
|
50567
|
-
if (
|
|
50567
|
+
if (flag2 === "--add-trigger" && parseEventKey(key) === null) {
|
|
50568
50568
|
throw new FunnelArgsError(`"${key}" is not an event key, so nothing would ever reach that step through it.`, {
|
|
50569
50569
|
action: "read_the_moments",
|
|
50570
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>."
|
|
@@ -50830,29 +50830,29 @@ function requireTarget5(args5, entity) {
|
|
|
50830
50830
|
}
|
|
50831
50831
|
return target2;
|
|
50832
50832
|
}
|
|
50833
|
-
function readJsonSource(args5,
|
|
50834
|
-
const inline = args5[
|
|
50833
|
+
function readJsonSource(args5, flag2) {
|
|
50834
|
+
const inline = args5[flag2];
|
|
50835
50835
|
const file = args5.file;
|
|
50836
50836
|
const raw = typeof file === "string" && file.length > 0 ? readFileSync17(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
50837
50837
|
if (raw === void 0) {
|
|
50838
|
-
failValidation3(`pass --${
|
|
50838
|
+
failValidation3(`pass --${flag2} with inline JSON or --file with a path to a JSON file`);
|
|
50839
50839
|
}
|
|
50840
50840
|
try {
|
|
50841
50841
|
return JSON.parse(raw);
|
|
50842
50842
|
} catch {
|
|
50843
|
-
return failValidation3(`--${
|
|
50843
|
+
return failValidation3(`--${flag2} is not valid JSON`);
|
|
50844
50844
|
}
|
|
50845
50845
|
}
|
|
50846
|
-
function asObject(value,
|
|
50846
|
+
function asObject(value, flag2, index) {
|
|
50847
50847
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
50848
50848
|
failValidation3(
|
|
50849
|
-
index === void 0 ? `--${
|
|
50849
|
+
index === void 0 ? `--${flag2} must be a JSON object` : `--${flag2}[${index}] must be a JSON object`
|
|
50850
50850
|
);
|
|
50851
50851
|
}
|
|
50852
50852
|
return value;
|
|
50853
50853
|
}
|
|
50854
|
-
function loadJsonArg(args5,
|
|
50855
|
-
return asObject(readJsonSource(args5,
|
|
50854
|
+
function loadJsonArg(args5, flag2 = "json") {
|
|
50855
|
+
return asObject(readJsonSource(args5, flag2), flag2);
|
|
50856
50856
|
}
|
|
50857
50857
|
function loadJsonPayloads(args5) {
|
|
50858
50858
|
const parsed = readJsonSource(args5, "json");
|
|
@@ -51702,18 +51702,18 @@ var RETENTION_BY_MONTHS = {
|
|
|
51702
51702
|
"38": "THIRTY_EIGHT_MONTHS",
|
|
51703
51703
|
"50": "FIFTY_MONTHS"
|
|
51704
51704
|
};
|
|
51705
|
-
function retentionValue(input,
|
|
51705
|
+
function retentionValue(input, flag2) {
|
|
51706
51706
|
const normalized = input.trim();
|
|
51707
51707
|
const mapped = RETENTION_BY_MONTHS[normalized] ?? (Object.values(RETENTION_BY_MONTHS).includes(normalized.toUpperCase()) ? normalized.toUpperCase() : void 0);
|
|
51708
51708
|
if (!mapped) {
|
|
51709
|
-
failValidation3(`--${
|
|
51709
|
+
failValidation3(`--${flag2} must be one of 2, 14, 26, 38 or 50 (months)`);
|
|
51710
51710
|
}
|
|
51711
51711
|
return mapped;
|
|
51712
51712
|
}
|
|
51713
|
-
function booleanArg(input,
|
|
51713
|
+
function booleanArg(input, flag2) {
|
|
51714
51714
|
if (input === "true") return true;
|
|
51715
51715
|
if (input === "false") return false;
|
|
51716
|
-
return failValidation3(`--${
|
|
51716
|
+
return failValidation3(`--${flag2} must be true or false`);
|
|
51717
51717
|
}
|
|
51718
51718
|
var dataRetentionCommand = defineCommand136({
|
|
51719
51719
|
meta: {
|
|
@@ -52049,10 +52049,10 @@ Examples:
|
|
|
52049
52049
|
},
|
|
52050
52050
|
run: async ({ args: args5 }) => {
|
|
52051
52051
|
const payload = {};
|
|
52052
|
-
for (const [
|
|
52053
|
-
const value = args5[
|
|
52052
|
+
for (const [flag2, field] of Object.entries(MEASUREMENT_FLAGS)) {
|
|
52053
|
+
const value = args5[flag2];
|
|
52054
52054
|
if (typeof value === "string") {
|
|
52055
|
-
payload[field] = booleanArg(value,
|
|
52055
|
+
payload[field] = booleanArg(value, flag2);
|
|
52056
52056
|
}
|
|
52057
52057
|
}
|
|
52058
52058
|
if (typeof args5["search-parameters"] === "string" && args5["search-parameters"].length > 0) {
|
|
@@ -52624,13 +52624,13 @@ var listCommand15 = defineCommand142({
|
|
|
52624
52624
|
run: async ({ args: args5 }) => {
|
|
52625
52625
|
try {
|
|
52626
52626
|
const body = {};
|
|
52627
|
-
const
|
|
52628
|
-
if (
|
|
52629
|
-
body.limit =
|
|
52627
|
+
const limit = parseBoundedInt2(args5.limit, "limit", 1, 200);
|
|
52628
|
+
if (limit !== void 0) {
|
|
52629
|
+
body.limit = limit;
|
|
52630
52630
|
}
|
|
52631
|
-
const
|
|
52632
|
-
if (
|
|
52633
|
-
body.days =
|
|
52631
|
+
const days = parseBoundedInt2(args5.days, "days", 1, 365);
|
|
52632
|
+
if (days !== void 0) {
|
|
52633
|
+
body.days = days;
|
|
52634
52634
|
}
|
|
52635
52635
|
if (args5.category) {
|
|
52636
52636
|
if (!CATEGORIES.includes(args5.category)) {
|
|
@@ -53015,20 +53015,20 @@ var formsSubmissionsCommand = defineCommand143({
|
|
|
53015
53015
|
},
|
|
53016
53016
|
run: async ({ args: args5 }) => {
|
|
53017
53017
|
try {
|
|
53018
|
-
const
|
|
53019
|
-
if (!Number.isInteger(
|
|
53018
|
+
const days = args5.days === void 0 ? 30 : Number(args5.days);
|
|
53019
|
+
if (!Number.isInteger(days) || days < 1 || days > 365) {
|
|
53020
53020
|
throw new ApiError("VALIDATION_ERROR", "--days must be a whole number between 1 and 365.");
|
|
53021
53021
|
}
|
|
53022
53022
|
const response = await apiPost("/api/hubspot/forms/submissions", {
|
|
53023
53023
|
formId: args5.formId,
|
|
53024
|
-
days
|
|
53024
|
+
days,
|
|
53025
53025
|
...args5.full ? { full: true } : {}
|
|
53026
53026
|
});
|
|
53027
53027
|
const { inWindow, total, truncated, lastSubmittedAt } = response.data;
|
|
53028
53028
|
const hints2 = [];
|
|
53029
53029
|
if (inWindow === 0) {
|
|
53030
53030
|
hints2.push(
|
|
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 ${
|
|
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 ${days} days, though the form has ${total} older submission(s). It worked once and has gone quiet.`
|
|
53032
53032
|
);
|
|
53033
53033
|
}
|
|
53034
53034
|
if (truncated) {
|
|
@@ -53215,15 +53215,15 @@ var contactsSummaryCommand = defineCommand143({
|
|
|
53215
53215
|
},
|
|
53216
53216
|
run: async ({ args: args5 }) => {
|
|
53217
53217
|
try {
|
|
53218
|
-
const
|
|
53219
|
-
if (!Number.isInteger(
|
|
53218
|
+
const days = args5.days === void 0 ? 30 : Number(args5.days);
|
|
53219
|
+
if (!Number.isInteger(days) || days < 1 || days > 365) {
|
|
53220
53220
|
throw new ApiError("VALIDATION_ERROR", "--days must be a whole number between 1 and 365.");
|
|
53221
53221
|
}
|
|
53222
|
-
const response = await apiPost("/api/hubspot/contacts/summary", { days
|
|
53222
|
+
const response = await apiPost("/api/hubspot/contacts/summary", { days });
|
|
53223
53223
|
const { total, withOwner, withoutOwner, byStage, truncated } = response.data;
|
|
53224
53224
|
const hints2 = [];
|
|
53225
53225
|
if (total === 0) {
|
|
53226
|
-
hints2.push(`No contacts were created in the last ${
|
|
53226
|
+
hints2.push(`No contacts were created in the last ${days} days \u2014 nothing reached the CRM in that window.`);
|
|
53227
53227
|
} else if (withOwner === 0) {
|
|
53228
53228
|
hints2.push(
|
|
53229
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.`
|
|
@@ -54308,7 +54308,7 @@ function emptyResultHints({ provider, hitCount, activeFilters, subject }) {
|
|
|
54308
54308
|
return hints2;
|
|
54309
54309
|
}
|
|
54310
54310
|
function activeFilterFlags(args5, candidates) {
|
|
54311
|
-
return candidates.filter((
|
|
54311
|
+
return candidates.filter((flag2) => args5[flag2] !== void 0 && args5[flag2] !== "").map((flag2) => `--${flag2}`);
|
|
54312
54312
|
}
|
|
54313
54313
|
|
|
54314
54314
|
// src/commands/images/find.ts
|
|
@@ -58661,8 +58661,8 @@ var favoritesCommand = defineCommand174({
|
|
|
58661
58661
|
const params2 = {};
|
|
58662
58662
|
const types = splitList2(args5.type);
|
|
58663
58663
|
if (types) params2.type = types.join(",");
|
|
58664
|
-
const
|
|
58665
|
-
if (
|
|
58664
|
+
const limit = parseNumber(args5.limit);
|
|
58665
|
+
if (limit !== void 0) params2.limit = String(limit);
|
|
58666
58666
|
const data = await apiGet("/api/landing-inspiration/favorites", params2);
|
|
58667
58667
|
const sections = Array.isArray(data?.sections) ? data.sections : [];
|
|
58668
58668
|
const full = args5.full;
|
|
@@ -60147,8 +60147,8 @@ var inPageSegment = (options) => {
|
|
|
60147
60147
|
};
|
|
60148
60148
|
const leaves = [];
|
|
60149
60149
|
const all = document.querySelectorAll("*");
|
|
60150
|
-
const
|
|
60151
|
-
for (let i = 0; i <
|
|
60150
|
+
const limit = Math.min(all.length, options.maxElements);
|
|
60151
|
+
for (let i = 0; i < limit; i++) {
|
|
60152
60152
|
const element = all[i];
|
|
60153
60153
|
if (!element) continue;
|
|
60154
60154
|
const tag = element.tagName.toLowerCase();
|
|
@@ -61233,8 +61233,8 @@ function buildSearchBody(args5) {
|
|
|
61233
61233
|
if (minCraft !== void 0) body.minCraftScore = minCraft;
|
|
61234
61234
|
const minFidelity = parseNumber(args5["min-fidelity"]);
|
|
61235
61235
|
if (minFidelity !== void 0) body.minFidelity = minFidelity;
|
|
61236
|
-
const
|
|
61237
|
-
body.limit =
|
|
61236
|
+
const limit = parseNumber(args5.limit);
|
|
61237
|
+
body.limit = limit ?? 8;
|
|
61238
61238
|
body.scope = args5.scope === "all" ? "all" : "favorites";
|
|
61239
61239
|
return body;
|
|
61240
61240
|
}
|
|
@@ -61381,8 +61381,8 @@ function buildSequencesBody(args5) {
|
|
|
61381
61381
|
const sectionType = splitList2(args5["section-type"]);
|
|
61382
61382
|
if (sectionType) body.sectionType = sectionType;
|
|
61383
61383
|
body.scope = args5.scope === "all" ? "all" : "favorites";
|
|
61384
|
-
const
|
|
61385
|
-
if (
|
|
61384
|
+
const limit = parseNumber(args5.limit);
|
|
61385
|
+
if (limit !== void 0) body.limit = limit;
|
|
61386
61386
|
else if (args5.full) body.limit = MAX_PAGES;
|
|
61387
61387
|
return body;
|
|
61388
61388
|
}
|
|
@@ -62439,7 +62439,7 @@ Examples:
|
|
|
62439
62439
|
const keyword = args5.keyword;
|
|
62440
62440
|
const location2 = args5.location || void 0;
|
|
62441
62441
|
const language = args5.language || void 0;
|
|
62442
|
-
const
|
|
62442
|
+
const limit = args5.limit ? Number(args5.limit) : void 0;
|
|
62443
62443
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
62444
62444
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
62445
62445
|
try {
|
|
@@ -62447,7 +62447,7 @@ Examples:
|
|
|
62447
62447
|
keyword,
|
|
62448
62448
|
location: location2,
|
|
62449
62449
|
language,
|
|
62450
|
-
limit
|
|
62450
|
+
limit,
|
|
62451
62451
|
skipCache
|
|
62452
62452
|
});
|
|
62453
62453
|
warnDefaults(queryContext);
|
|
@@ -62517,7 +62517,7 @@ Examples:
|
|
|
62517
62517
|
const keyword = args5.keyword;
|
|
62518
62518
|
const location2 = args5.location || void 0;
|
|
62519
62519
|
const language = args5.language || void 0;
|
|
62520
|
-
const
|
|
62520
|
+
const limit = args5.limit ? Number(args5.limit) : void 0;
|
|
62521
62521
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
62522
62522
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
62523
62523
|
try {
|
|
@@ -62525,7 +62525,7 @@ Examples:
|
|
|
62525
62525
|
keyword,
|
|
62526
62526
|
location: location2,
|
|
62527
62527
|
language,
|
|
62528
|
-
limit
|
|
62528
|
+
limit,
|
|
62529
62529
|
skipCache
|
|
62530
62530
|
});
|
|
62531
62531
|
warnDefaults(queryContext);
|
|
@@ -62896,7 +62896,7 @@ Examples:
|
|
|
62896
62896
|
const location2 = args5.location || void 0;
|
|
62897
62897
|
const language = args5.language || void 0;
|
|
62898
62898
|
const type = args5.type || void 0;
|
|
62899
|
-
const
|
|
62899
|
+
const limit = args5.limit ? Number(args5.limit) : void 0;
|
|
62900
62900
|
const offset = args5.offset ? Number(args5.offset) : void 0;
|
|
62901
62901
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
62902
62902
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
@@ -62907,12 +62907,12 @@ Examples:
|
|
|
62907
62907
|
location: location2,
|
|
62908
62908
|
language,
|
|
62909
62909
|
type,
|
|
62910
|
-
limit
|
|
62910
|
+
limit,
|
|
62911
62911
|
offset,
|
|
62912
62912
|
skipCache
|
|
62913
62913
|
});
|
|
62914
62914
|
const currentOffset = offset ?? 0;
|
|
62915
|
-
const currentLimit =
|
|
62915
|
+
const currentLimit = limit ?? 50;
|
|
62916
62916
|
const hasMore = currentOffset + result.data.length < result.total_count;
|
|
62917
62917
|
warnDefaults(queryContext);
|
|
62918
62918
|
const format = args5.output || "json";
|
|
@@ -63165,7 +63165,7 @@ Examples:
|
|
|
63165
63165
|
const language = args5.language || void 0;
|
|
63166
63166
|
const sort = args5.sort || void 0;
|
|
63167
63167
|
const type = args5.type || void 0;
|
|
63168
|
-
const
|
|
63168
|
+
const limit = args5.limit ? Number(args5.limit) : void 0;
|
|
63169
63169
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
63170
63170
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63171
63171
|
try {
|
|
@@ -63175,7 +63175,7 @@ Examples:
|
|
|
63175
63175
|
language,
|
|
63176
63176
|
sort,
|
|
63177
63177
|
type,
|
|
63178
|
-
limit
|
|
63178
|
+
limit,
|
|
63179
63179
|
skipCache
|
|
63180
63180
|
});
|
|
63181
63181
|
warnDefaults(queryContext);
|
|
@@ -63346,7 +63346,7 @@ Examples:
|
|
|
63346
63346
|
const target2 = args5.target;
|
|
63347
63347
|
const location2 = args5.location || void 0;
|
|
63348
63348
|
const language = args5.language || void 0;
|
|
63349
|
-
const
|
|
63349
|
+
const limit = args5.limit ? Number(args5.limit) : void 0;
|
|
63350
63350
|
const skipCache = args5["no-cache"] ? true : void 0;
|
|
63351
63351
|
const queryContext = buildResearchQueryContext(location2, language);
|
|
63352
63352
|
try {
|
|
@@ -63354,7 +63354,7 @@ Examples:
|
|
|
63354
63354
|
target: target2,
|
|
63355
63355
|
location: location2,
|
|
63356
63356
|
language,
|
|
63357
|
-
limit
|
|
63357
|
+
limit,
|
|
63358
63358
|
skipCache
|
|
63359
63359
|
});
|
|
63360
63360
|
warnDefaults(queryContext);
|
|
@@ -63700,13 +63700,13 @@ function refuseMisusedKinds(kind, args5) {
|
|
|
63700
63700
|
function refuseStrayFlags(kind, args5) {
|
|
63701
63701
|
const allowed = new Set(TRIGGER_TARGETS[kind].map((target2) => TRIGGER_TARGET_FIELDS[target2.field].flag));
|
|
63702
63702
|
const stray = TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag).filter(
|
|
63703
|
-
(
|
|
63703
|
+
(flag2) => !allowed.has(flag2) && flagText(args5, flag2) !== void 0 && !(kind === "experiment.started" && flag2 === "experiment")
|
|
63704
63704
|
);
|
|
63705
63705
|
if (stray.length === 0) {
|
|
63706
63706
|
return;
|
|
63707
63707
|
}
|
|
63708
63708
|
failValidation4(
|
|
63709
|
-
`${stray.map((
|
|
63709
|
+
`${stray.map((flag2) => `--${flag2}`).join(", ")} does not narrow ${kind}. ${allowed.size > 0 ? `It can be pointed with ${[...allowed].map((flag2) => `--${flag2}`).join(", ")}.` : "It runs every time it happens \u2014 narrow it with --when rules over its payload instead."}`
|
|
63710
63710
|
);
|
|
63711
63711
|
}
|
|
63712
63712
|
var NARROWING_FLAGS = [...TRIGGER_TARGET_FIELD_IDS.map((field) => TRIGGER_TARGET_FIELDS[field].flag), "config"];
|
|
@@ -63714,11 +63714,11 @@ function refuseNarrowingWithoutKind(args5, kind, given) {
|
|
|
63714
63714
|
if (kind) {
|
|
63715
63715
|
return;
|
|
63716
63716
|
}
|
|
63717
|
-
const stray = NARROWING_FLAGS.filter((
|
|
63717
|
+
const stray = NARROWING_FLAGS.filter((flag2) => flagText(args5, flag2) !== void 0);
|
|
63718
63718
|
if (stray.length === 0) {
|
|
63719
63719
|
return;
|
|
63720
63720
|
}
|
|
63721
|
-
const flags = stray.map((
|
|
63721
|
+
const flags = stray.map((flag2) => `--${flag2}`).join(", ");
|
|
63722
63722
|
failValidation4(
|
|
63723
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.`
|
|
63724
63724
|
);
|
|
@@ -63809,13 +63809,13 @@ var REACTION_ARGS = {
|
|
|
63809
63809
|
required: false
|
|
63810
63810
|
}
|
|
63811
63811
|
};
|
|
63812
|
-
function wholeNumber(raw,
|
|
63812
|
+
function wholeNumber(raw, flag2, { min }) {
|
|
63813
63813
|
if (raw === void 0) {
|
|
63814
63814
|
return void 0;
|
|
63815
63815
|
}
|
|
63816
63816
|
const value = Number(raw);
|
|
63817
63817
|
if (!Number.isInteger(value) || value < min) {
|
|
63818
|
-
failValidation4(`${
|
|
63818
|
+
failValidation4(`${flag2} must be a whole number of at least ${min}.`);
|
|
63819
63819
|
}
|
|
63820
63820
|
return value;
|
|
63821
63821
|
}
|
|
@@ -64285,31 +64285,31 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64285
64285
|
delete: { type: "string", description: "Remove one of this company's own, by id", required: false }
|
|
64286
64286
|
},
|
|
64287
64287
|
run: async ({ args: args5 }) => {
|
|
64288
|
-
const
|
|
64288
|
+
const flag2 = (key) => {
|
|
64289
64289
|
const value = args5[key];
|
|
64290
64290
|
return typeof value === "string" ? value.trim() : "";
|
|
64291
64291
|
};
|
|
64292
64292
|
try {
|
|
64293
|
-
const save =
|
|
64294
|
-
const publish =
|
|
64295
|
-
const remove =
|
|
64293
|
+
const save = flag2("save");
|
|
64294
|
+
const publish = flag2("publish");
|
|
64295
|
+
const remove = flag2("delete");
|
|
64296
64296
|
if ([save, publish, remove].filter((id) => id.length > 0).length > 1) {
|
|
64297
64297
|
failValidation4("Pass one of --save, --publish or --delete at a time.");
|
|
64298
64298
|
}
|
|
64299
64299
|
if (save.length > 0) {
|
|
64300
|
-
const briefFile =
|
|
64301
|
-
const brief2 = briefFile.length > 0 ? await readFile32(path46.resolve(briefFile), "utf8") :
|
|
64300
|
+
const briefFile = flag2("brief-file");
|
|
64301
|
+
const brief2 = briefFile.length > 0 ? await readFile32(path46.resolve(briefFile), "utf8") : flag2("brief");
|
|
64302
64302
|
if (brief2.trim().length === 0) {
|
|
64303
64303
|
failValidation4("--brief-file (preferred) or --brief is required: the brief is the recipe.");
|
|
64304
64304
|
}
|
|
64305
64305
|
const response2 = await apiPost("/api/marketplace/save", {
|
|
64306
64306
|
chatId: requireChatId(),
|
|
64307
64307
|
slug: save,
|
|
64308
|
-
name:
|
|
64309
|
-
category:
|
|
64310
|
-
tagline:
|
|
64308
|
+
name: flag2("name"),
|
|
64309
|
+
category: flag2("recipe-category"),
|
|
64310
|
+
tagline: flag2("tagline"),
|
|
64311
64311
|
prompt: brief2,
|
|
64312
|
-
frequency:
|
|
64312
|
+
frequency: flag2("frequency")
|
|
64313
64313
|
});
|
|
64314
64314
|
writeJson(response2);
|
|
64315
64315
|
return;
|
|
@@ -64330,7 +64330,7 @@ Full guide: __tooling__/docs/tools/baker/scheduled-agents.md`
|
|
|
64330
64330
|
writeJson(response2);
|
|
64331
64331
|
return;
|
|
64332
64332
|
}
|
|
64333
|
-
const category =
|
|
64333
|
+
const category = flag2("category");
|
|
64334
64334
|
const response = await apiPost("/api/marketplace/list", {
|
|
64335
64335
|
...category.length > 0 ? { category } : {},
|
|
64336
64336
|
...args5.drafts === true ? { drafts: true } : {}
|
|
@@ -64622,150 +64622,6 @@ var schemaCommand2 = defineCommand208({
|
|
|
64622
64622
|
}
|
|
64623
64623
|
});
|
|
64624
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
|
-
|
|
64769
64625
|
// ../api/src/shopify/wire.ts
|
|
64770
64626
|
import { z as z50 } from "zod";
|
|
64771
64627
|
var SHOPIFY_NOT_CONNECTED_MESSAGE = "No Shopify store is connected for this company.";
|
|
@@ -65143,42 +64999,13 @@ var shopifyStockResponseSchema = z50.object({
|
|
|
65143
64999
|
/** More products in that group than `limit`. */
|
|
65144
65000
|
more: z50.object({ outOfStock: z50.boolean(), partlyOut: z50.boolean() })
|
|
65145
65001
|
});
|
|
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"];
|
|
65002
|
+
var shopifySalesBySchema = z50.enum(["day", "product", "campaign", "landing"]);
|
|
65157
65003
|
var SHOPIFY_SALES_MAX_DAYS = 395;
|
|
65158
|
-
var SHOPIFY_SALES_TIMING_MAX_DAYS = 3650;
|
|
65159
65004
|
var shopifySalesRequestSchema = z50.object({
|
|
65160
|
-
days: z50.coerce.number().int().min(1).max(
|
|
65161
|
-
/** Every order the store has (timing breakdowns only). */
|
|
65162
|
-
all: flag.optional(),
|
|
65005
|
+
days: z50.coerce.number().int().min(1).max(SHOPIFY_SALES_MAX_DAYS).optional(),
|
|
65163
65006
|
by: shopifySalesBySchema.optional(),
|
|
65164
65007
|
limit: z50.coerce.number().int().min(1).max(100).optional(),
|
|
65165
65008
|
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
65009
|
});
|
|
65183
65010
|
var shopifySalesCreditSchema = z50.enum([
|
|
65184
65011
|
"campaign",
|
|
@@ -65201,8 +65028,6 @@ var shopifySalesRowSchema = z50.object({
|
|
|
65201
65028
|
/** By product: units sold and given back. */
|
|
65202
65029
|
units: z50.number().optional(),
|
|
65203
65030
|
refundedUnits: z50.number().optional(),
|
|
65204
|
-
/** By weekday, hour or month: the buyers who ordered. */
|
|
65205
|
-
buyers: z50.number().optional(),
|
|
65206
65031
|
// --full
|
|
65207
65032
|
source: z50.string().optional(),
|
|
65208
65033
|
medium: z50.string().optional(),
|
|
@@ -65223,13 +65048,7 @@ var shopifySalesTotalsSchema = z50.object({
|
|
|
65223
65048
|
var shopifySalesReportingSchema = z50.enum(["shopify_channel", "baker", "undecided"]);
|
|
65224
65049
|
var shopifySalesResponseSchema = z50.object({
|
|
65225
65050
|
store: shopifyStoreStateSchema,
|
|
65226
|
-
|
|
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
|
-
}),
|
|
65051
|
+
window: z50.object({ days: z50.number(), from: z50.string(), to: z50.string() }),
|
|
65233
65052
|
by: shopifySalesBySchema,
|
|
65234
65053
|
/** The store's currency; null when nothing sold in the window. */
|
|
65235
65054
|
currency: z50.string().nullable(),
|
|
@@ -65244,442 +65063,8 @@ var shopifySalesResponseSchema = z50.object({
|
|
|
65244
65063
|
ordersUnreadable: z50.literal(true).optional()
|
|
65245
65064
|
});
|
|
65246
65065
|
|
|
65247
|
-
//
|
|
65248
|
-
|
|
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
|
-
});
|
|
65614
|
-
|
|
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
|
-
};
|
|
65066
|
+
// src/commands/shopify/index.ts
|
|
65067
|
+
import { defineCommand as defineCommand209 } from "citty";
|
|
65683
65068
|
|
|
65684
65069
|
// src/commands/shopify/hints.ts
|
|
65685
65070
|
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.';
|
|
@@ -65864,7 +65249,7 @@ function productHints(product, store) {
|
|
|
65864
65249
|
}
|
|
65865
65250
|
return hints2;
|
|
65866
65251
|
}
|
|
65867
|
-
function stockHints(answer,
|
|
65252
|
+
function stockHints(answer, limit) {
|
|
65868
65253
|
const hints2 = [];
|
|
65869
65254
|
const any = answer.outOfStock.length > 0 || answer.partlyOut.length > 0;
|
|
65870
65255
|
const unfinished = answer.more.outOfStock || answer.more.partlyOut;
|
|
@@ -65875,9 +65260,9 @@ function stockHints(answer, limit2) {
|
|
|
65875
65260
|
);
|
|
65876
65261
|
} else if (!unfinished) hints2.push("Nothing is out of stock.");
|
|
65877
65262
|
if (unfinished) {
|
|
65878
|
-
const full = answer.more.outOfStock && answer.outOfStock.length >=
|
|
65263
|
+
const full = answer.more.outOfStock && answer.outOfStock.length >= limit || answer.more.partlyOut && answer.partlyOut.length >= limit;
|
|
65879
65264
|
hints2.push(
|
|
65880
|
-
full ? `More than ${
|
|
65265
|
+
full ? `More than ${limit} 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}.`
|
|
65881
65266
|
);
|
|
65882
65267
|
}
|
|
65883
65268
|
const big = answer.partlyOut.find((row) => row.outOptionsMore);
|
|
@@ -65912,12 +65297,6 @@ function storeHints(summary) {
|
|
|
65912
65297
|
}
|
|
65913
65298
|
return hints2;
|
|
65914
65299
|
}
|
|
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
65300
|
function salesHints(answer) {
|
|
65922
65301
|
const hints2 = [];
|
|
65923
65302
|
if (answer.ordersUnreadable) {
|
|
@@ -65934,9 +65313,6 @@ function salesHints(answer) {
|
|
|
65934
65313
|
hints2.push("No orders were paid in this period.");
|
|
65935
65314
|
return hints2;
|
|
65936
65315
|
}
|
|
65937
|
-
if (answer.by === "weekday" || answer.by === "hour" || answer.by === "month_of_year") {
|
|
65938
|
-
return [...hints2, ...timingHints(answer)];
|
|
65939
|
-
}
|
|
65940
65316
|
const notBaker = ["meta", "google"].filter((family) => answer.salesReporting[family] !== "baker");
|
|
65941
65317
|
if (notBaker.length > 0) {
|
|
65942
65318
|
const names = notBaker.map((family) => family === "meta" ? "Meta" : "Google").join(" and ");
|
|
@@ -65959,303 +65335,64 @@ function salesHints(answer) {
|
|
|
65959
65335
|
return hints2;
|
|
65960
65336
|
}
|
|
65961
65337
|
|
|
65962
|
-
// src/commands/shopify/
|
|
65963
|
-
var
|
|
65964
|
-
|
|
65965
|
-
|
|
65966
|
-
|
|
65967
|
-
|
|
65968
|
-
|
|
65969
|
-
|
|
65970
|
-
|
|
65971
|
-
|
|
65972
|
-
}
|
|
65973
|
-
|
|
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"
|
|
66015
|
-
}
|
|
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);
|
|
66054
|
-
}
|
|
66055
|
-
}
|
|
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" }
|
|
66063
|
-
}
|
|
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" }
|
|
65338
|
+
// src/commands/shopify/refusal.ts
|
|
65339
|
+
var CONTINUE2 = "Keep going with the wider task: say which part you could not read, skip it, and finish everything else.";
|
|
65340
|
+
function shopifyRefusal(code, message) {
|
|
65341
|
+
if (code !== "NOT_FOUND") return null;
|
|
65342
|
+
if (message.includes(SHOPIFY_NOT_CONNECTED_MESSAGE)) {
|
|
65343
|
+
return {
|
|
65344
|
+
code: "NO_SHOPIFY_CONNECTION",
|
|
65345
|
+
fix: {
|
|
65346
|
+
action: "request_connection",
|
|
65347
|
+
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
|
|
65348
|
+
}
|
|
65349
|
+
};
|
|
66151
65350
|
}
|
|
66152
|
-
|
|
66153
|
-
|
|
66154
|
-
|
|
66155
|
-
|
|
66156
|
-
|
|
66157
|
-
|
|
66158
|
-
|
|
66159
|
-
|
|
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
|
-
}
|
|
65351
|
+
if (message.includes(SHOPIFY_NOT_OFFERED_MESSAGE)) {
|
|
65352
|
+
return {
|
|
65353
|
+
code: "SHOPIFY_NOT_AVAILABLE",
|
|
65354
|
+
fix: {
|
|
65355
|
+
action: "continue_without",
|
|
65356
|
+
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."
|
|
65357
|
+
}
|
|
65358
|
+
};
|
|
66190
65359
|
}
|
|
66191
|
-
|
|
66192
|
-
|
|
66193
|
-
|
|
66194
|
-
|
|
66195
|
-
|
|
66196
|
-
|
|
66197
|
-
|
|
66198
|
-
|
|
66199
|
-
|
|
66200
|
-
|
|
65360
|
+
return null;
|
|
65361
|
+
}
|
|
65362
|
+
|
|
65363
|
+
// src/commands/shopify/index.ts
|
|
65364
|
+
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.";
|
|
65365
|
+
function fail9(err) {
|
|
65366
|
+
if (err instanceof ApiError) {
|
|
65367
|
+
const refusal = shopifyRefusal(err.code, err.message);
|
|
65368
|
+
if (refusal) {
|
|
65369
|
+
writeJson({ ok: false, error: { code: refusal.code, message: err.message, fix: refusal.fix } });
|
|
65370
|
+
process.exit(1);
|
|
66201
65371
|
}
|
|
66202
|
-
|
|
66203
|
-
});
|
|
66204
|
-
|
|
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);
|
|
65372
|
+
if (err.code === "NOT_FOUND" && err.message.startsWith(SHOPIFY_PRODUCT_NOT_FOUND_PREFIX)) {
|
|
65373
|
+
writeJson({ ok: false, error: { code: err.code, message: err.message }, hints: [PRODUCT_NOT_FOUND_HINT] });
|
|
65374
|
+
process.exit(1);
|
|
66224
65375
|
}
|
|
66225
65376
|
}
|
|
66226
|
-
|
|
66227
|
-
|
|
66228
|
-
|
|
66229
|
-
|
|
66230
|
-
|
|
66231
|
-
|
|
66232
|
-
|
|
66233
|
-
|
|
66234
|
-
|
|
66235
|
-
|
|
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
|
-
}
|
|
65377
|
+
failApi(err);
|
|
65378
|
+
}
|
|
65379
|
+
function emit2(data, meta, hints2) {
|
|
65380
|
+
writeJson({ ok: true, data, meta, ...hints2.length > 0 ? { hints: hints2 } : {} });
|
|
65381
|
+
}
|
|
65382
|
+
function params(entries) {
|
|
65383
|
+
const out = {};
|
|
65384
|
+
for (const [name, value] of Object.entries(entries)) {
|
|
65385
|
+
if (value === void 0 || value === "" || value === false) continue;
|
|
65386
|
+
out[name] = String(value);
|
|
66255
65387
|
}
|
|
66256
|
-
|
|
66257
|
-
|
|
66258
|
-
|
|
65388
|
+
return out;
|
|
65389
|
+
}
|
|
65390
|
+
var fullArg = {
|
|
65391
|
+
type: "boolean",
|
|
65392
|
+
description: "Everything Baker keeps, not just what answers the question",
|
|
65393
|
+
required: false,
|
|
65394
|
+
default: false
|
|
65395
|
+
};
|
|
66259
65396
|
registerSchema({
|
|
66260
65397
|
command: "shopify.store",
|
|
66261
65398
|
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.',
|
|
@@ -66353,24 +65490,14 @@ registerSchema({
|
|
|
66353
65490
|
});
|
|
66354
65491
|
registerSchema({
|
|
66355
65492
|
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.
|
|
65493
|
+
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.",
|
|
66357
65494
|
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
|
-
},
|
|
65495
|
+
days: { type: "number", description: "The last N days, 1-395 (default 30)", required: false },
|
|
66369
65496
|
by: {
|
|
66370
65497
|
type: "string",
|
|
66371
|
-
description: "day | product | campaign | landing
|
|
65498
|
+
description: "day | product | campaign | landing (default day)",
|
|
66372
65499
|
required: false,
|
|
66373
|
-
enum: ["day", "product", "campaign", "landing"
|
|
65500
|
+
enum: ["day", "product", "campaign", "landing"]
|
|
66374
65501
|
},
|
|
66375
65502
|
limit: {
|
|
66376
65503
|
type: "number",
|
|
@@ -66383,28 +65510,14 @@ registerSchema({
|
|
|
66383
65510
|
}
|
|
66384
65511
|
}
|
|
66385
65512
|
});
|
|
66386
|
-
var salesCommand =
|
|
65513
|
+
var salesCommand = defineCommand209({
|
|
66387
65514
|
meta: {
|
|
66388
65515
|
name: "sales",
|
|
66389
|
-
description: "What the store sold: orders, sales, refunds and net, by day, product, campaign or landing
|
|
65516
|
+
description: "What the store sold: orders, sales, refunds and net, by day, product, campaign or landing. Example: baker shopify sales --days 7 --by campaign"
|
|
66390
65517
|
},
|
|
66391
65518
|
args: {
|
|
66392
|
-
days: {
|
|
66393
|
-
|
|
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
|
-
},
|
|
65519
|
+
days: { type: "string", description: "The last N days, 1-395 (default 30)", required: false },
|
|
65520
|
+
by: { type: "string", description: "day | product | campaign | landing (default day)", required: false },
|
|
66408
65521
|
limit: { type: "string", description: "Rows of a breakdown, 1-100", required: false },
|
|
66409
65522
|
full: { type: "boolean", description: "Add sources, campaigns and ids per row", required: false, default: false }
|
|
66410
65523
|
},
|
|
@@ -66412,7 +65525,7 @@ var salesCommand = defineCommand210({
|
|
|
66412
65525
|
try {
|
|
66413
65526
|
const answer = await apiGet(
|
|
66414
65527
|
"/api/shopify/sales",
|
|
66415
|
-
params({ days: args5.days,
|
|
65528
|
+
params({ days: args5.days, by: args5.by, limit: args5.limit, full: args5.full })
|
|
66416
65529
|
);
|
|
66417
65530
|
const { store, salesReporting, history, ...data } = answer;
|
|
66418
65531
|
emit2(data, { store, salesReporting, history }, [...storeStateHints(store), ...salesHints(answer)]);
|
|
@@ -66421,7 +65534,7 @@ var salesCommand = defineCommand210({
|
|
|
66421
65534
|
}
|
|
66422
65535
|
}
|
|
66423
65536
|
});
|
|
66424
|
-
var storeCommand =
|
|
65537
|
+
var storeCommand = defineCommand209({
|
|
66425
65538
|
meta: {
|
|
66426
65539
|
name: "store",
|
|
66427
65540
|
description: "The connected Shopify store: currency, countries, how many products, what is out of stock. Example: baker shopify store"
|
|
@@ -66438,7 +65551,7 @@ var storeCommand = defineCommand210({
|
|
|
66438
65551
|
}
|
|
66439
65552
|
}
|
|
66440
65553
|
});
|
|
66441
|
-
var productsCommand =
|
|
65554
|
+
var productsCommand = defineCommand209({
|
|
66442
65555
|
meta: {
|
|
66443
65556
|
name: "products",
|
|
66444
65557
|
description: 'What the store sells, with price and stock. Example: baker shopify products --search "snowboard" --stock out_of_stock'
|
|
@@ -66484,7 +65597,7 @@ var productsCommand = defineCommand210({
|
|
|
66484
65597
|
}
|
|
66485
65598
|
}
|
|
66486
65599
|
});
|
|
66487
|
-
var productCommand =
|
|
65600
|
+
var productCommand = defineCommand209({
|
|
66488
65601
|
meta: {
|
|
66489
65602
|
name: "product",
|
|
66490
65603
|
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"
|
|
@@ -66547,7 +65660,7 @@ var productCommand = defineCommand210({
|
|
|
66547
65660
|
}
|
|
66548
65661
|
}
|
|
66549
65662
|
});
|
|
66550
|
-
var collectionsCommand =
|
|
65663
|
+
var collectionsCommand = defineCommand209({
|
|
66551
65664
|
meta: {
|
|
66552
65665
|
name: "collections",
|
|
66553
65666
|
description: "The store's collections, with the handles --collection takes. Example: baker shopify collections --full"
|
|
@@ -66572,7 +65685,7 @@ var collectionsCommand = defineCommand210({
|
|
|
66572
65685
|
}
|
|
66573
65686
|
}
|
|
66574
65687
|
});
|
|
66575
|
-
var stockCommand2 =
|
|
65688
|
+
var stockCommand2 = defineCommand209({
|
|
66576
65689
|
meta: {
|
|
66577
65690
|
name: "stock",
|
|
66578
65691
|
description: "Every product with options out of stock, naming them. Example: baker shopify stock"
|
|
@@ -66589,18 +65702,18 @@ var stockCommand2 = defineCommand210({
|
|
|
66589
65702
|
params({ collection: args5.collection, limit: args5.limit, full: args5.full })
|
|
66590
65703
|
);
|
|
66591
65704
|
const { store, ...data } = answer;
|
|
66592
|
-
const
|
|
66593
|
-
emit2(data, { store }, [...storeStateHints(store), ...stockHints(answer, Number.isFinite(
|
|
65705
|
+
const limit = Number(args5.limit ?? 50);
|
|
65706
|
+
emit2(data, { store }, [...storeStateHints(store), ...stockHints(answer, Number.isFinite(limit) ? limit : 50)]);
|
|
66594
65707
|
} catch (err) {
|
|
66595
65708
|
fail9(err);
|
|
66596
65709
|
}
|
|
66597
65710
|
}
|
|
66598
65711
|
});
|
|
66599
|
-
var shopifyCommand =
|
|
65712
|
+
var shopifyCommand = defineCommand209({
|
|
66600
65713
|
meta: {
|
|
66601
65714
|
name: "shopify",
|
|
66602
65715
|
description: `Read the connected Shopify store as Baker keeps it \u2014 products, prices by country, stock, collections,
|
|
66603
|
-
product photos
|
|
65716
|
+
product photos and what it sold. Read-only: nothing here changes the store.
|
|
66604
65717
|
|
|
66605
65718
|
Examples:
|
|
66606
65719
|
baker shopify store # currency, countries, how many products, what is out of stock
|
|
@@ -66615,13 +65728,6 @@ Examples:
|
|
|
66615
65728
|
baker shopify stock # every product with options out of stock
|
|
66616
65729
|
baker shopify collections # collections, with handles for --collection
|
|
66617
65730
|
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
|
|
66625
65731
|
|
|
66626
65732
|
Product photos are already in the image library: place them by imageId
|
|
66627
65733
|
(baker images download <imageIds> --out src/pages/<page>/_images/), never by a cdn.shopify.com link.
|
|
@@ -66638,21 +65744,15 @@ Full guide: __tooling__/docs/tools/baker/shopify.md`
|
|
|
66638
65744
|
product: productCommand,
|
|
66639
65745
|
collections: collectionsCommand,
|
|
66640
65746
|
stock: stockCommand2,
|
|
66641
|
-
sales: salesCommand
|
|
66642
|
-
buyers: buyersCommand,
|
|
66643
|
-
buyer: buyerCommand,
|
|
66644
|
-
countries: countriesCommand2,
|
|
66645
|
-
"best-sellers": bestSellersCommand,
|
|
66646
|
-
cohorts: cohortsCommand,
|
|
66647
|
-
segments: segmentsCommand
|
|
65747
|
+
sales: salesCommand
|
|
66648
65748
|
}
|
|
66649
65749
|
});
|
|
66650
65750
|
|
|
66651
65751
|
// src/commands/studio/index.ts
|
|
66652
|
-
import { defineCommand as
|
|
65752
|
+
import { defineCommand as defineCommand218 } from "citty";
|
|
66653
65753
|
|
|
66654
65754
|
// src/commands/studio/animate.ts
|
|
66655
|
-
import { defineCommand as
|
|
65755
|
+
import { defineCommand as defineCommand210 } from "citty";
|
|
66656
65756
|
|
|
66657
65757
|
// src/commands/studio/spokenPace.ts
|
|
66658
65758
|
var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
|
|
@@ -66663,9 +65763,9 @@ function wordsThatFit(seconds) {
|
|
|
66663
65763
|
function spokenPaceHint(prompt, seconds, model) {
|
|
66664
65764
|
const words2 = spokenWords(prompt);
|
|
66665
65765
|
if (words2 === 0) return null;
|
|
66666
|
-
const
|
|
66667
|
-
if (
|
|
66668
|
-
return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${
|
|
65766
|
+
const split = model ? splitScriptFor(words2, model) : null;
|
|
65767
|
+
if (split) {
|
|
65768
|
+
return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${split.maxSeconds}s (~${Math.floor(split.maxSeconds * WORDS_PER_SECOND3)} words). It will not refuse and it will not cut: it will RUSH, swallowing syllables. Split the script into ${split.clips} takes of roughly ${split.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).`;
|
|
66669
65769
|
}
|
|
66670
65770
|
if (!seconds) return null;
|
|
66671
65771
|
const fits = wordsThatFit(seconds);
|
|
@@ -66880,10 +65980,10 @@ var defaultDeps = {
|
|
|
66880
65980
|
ingest: (url) => apiPost("/api/images/ingest", { url, source: "uploaded" }),
|
|
66881
65981
|
upload: (path48) => uploadLocalImage({ file: path48, contentType: detectImageContentType(path48), source: "uploaded" })
|
|
66882
65982
|
};
|
|
66883
|
-
async function resolveLibraryImageIds(spec,
|
|
65983
|
+
async function resolveLibraryImageIds(spec, limit, deps = defaultDeps) {
|
|
66884
65984
|
const refs = parseImageRefs(spec);
|
|
66885
|
-
if (
|
|
66886
|
-
throw new ApiError("VALIDATION_ERROR",
|
|
65985
|
+
if (limit && refs.length > limit.max) {
|
|
65986
|
+
throw new ApiError("VALIDATION_ERROR", limit.refuse(refs.length));
|
|
66887
65987
|
}
|
|
66888
65988
|
const imageIds = [];
|
|
66889
65989
|
const added = [];
|
|
@@ -67165,7 +66265,7 @@ async function adByHandHintFor(body) {
|
|
|
67165
66265
|
return null;
|
|
67166
66266
|
}
|
|
67167
66267
|
}
|
|
67168
|
-
var animateCommand =
|
|
66268
|
+
var animateCommand = defineCommand210({
|
|
67169
66269
|
meta: {
|
|
67170
66270
|
name: "animate",
|
|
67171
66271
|
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"
|
|
@@ -67290,7 +66390,7 @@ var animateCommand = defineCommand211({
|
|
|
67290
66390
|
});
|
|
67291
66391
|
|
|
67292
66392
|
// src/commands/studio/generate.ts
|
|
67293
|
-
import { defineCommand as
|
|
66393
|
+
import { defineCommand as defineCommand211 } from "citty";
|
|
67294
66394
|
var MODEL_LIST2 = IMAGE_MODEL_IDS;
|
|
67295
66395
|
var DEFAULT_MAX_WAIT_MS2 = 24e4;
|
|
67296
66396
|
registerSchema({
|
|
@@ -67378,11 +66478,11 @@ registerSchema({
|
|
|
67378
66478
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
67379
66479
|
}
|
|
67380
66480
|
});
|
|
67381
|
-
function parseJsonArg(raw,
|
|
66481
|
+
function parseJsonArg(raw, flag2) {
|
|
67382
66482
|
try {
|
|
67383
66483
|
return JSON.parse(raw);
|
|
67384
66484
|
} catch {
|
|
67385
|
-
throw new ApiError("VALIDATION_ERROR", `--${
|
|
66485
|
+
throw new ApiError("VALIDATION_ERROR", `--${flag2} must be valid JSON (got: ${raw})`);
|
|
67386
66486
|
}
|
|
67387
66487
|
}
|
|
67388
66488
|
function referenceLimitFor(model) {
|
|
@@ -67426,7 +66526,7 @@ function buildGenerateBody(args5, prompt) {
|
|
|
67426
66526
|
}
|
|
67427
66527
|
return body;
|
|
67428
66528
|
}
|
|
67429
|
-
var generateCommand =
|
|
66529
|
+
var generateCommand = defineCommand211({
|
|
67430
66530
|
meta: {
|
|
67431
66531
|
name: "generate",
|
|
67432
66532
|
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]]'"
|
|
@@ -67509,7 +66609,7 @@ var generateCommand = defineCommand212({
|
|
|
67509
66609
|
});
|
|
67510
66610
|
|
|
67511
66611
|
// src/commands/studio/get.ts
|
|
67512
|
-
import { defineCommand as
|
|
66612
|
+
import { defineCommand as defineCommand212 } from "citty";
|
|
67513
66613
|
registerSchema({
|
|
67514
66614
|
command: "studio.get",
|
|
67515
66615
|
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.",
|
|
@@ -67518,7 +66618,7 @@ registerSchema({
|
|
|
67518
66618
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
67519
66619
|
}
|
|
67520
66620
|
});
|
|
67521
|
-
var getCommand5 =
|
|
66621
|
+
var getCommand5 = defineCommand212({
|
|
67522
66622
|
meta: {
|
|
67523
66623
|
name: "get",
|
|
67524
66624
|
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"
|
|
@@ -67547,7 +66647,7 @@ var getCommand5 = defineCommand213({
|
|
|
67547
66647
|
});
|
|
67548
66648
|
|
|
67549
66649
|
// src/commands/studio/improve.ts
|
|
67550
|
-
import { defineCommand as
|
|
66650
|
+
import { defineCommand as defineCommand213 } from "citty";
|
|
67551
66651
|
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.";
|
|
67552
66652
|
registerSchema({
|
|
67553
66653
|
command: "studio.improve",
|
|
@@ -67572,7 +66672,7 @@ registerSchema({
|
|
|
67572
66672
|
}
|
|
67573
66673
|
}
|
|
67574
66674
|
});
|
|
67575
|
-
var improveCommand =
|
|
66675
|
+
var improveCommand = defineCommand213({
|
|
67576
66676
|
meta: {
|
|
67577
66677
|
name: "improve",
|
|
67578
66678
|
description: `${DESCRIPTION2}
|
|
@@ -67616,7 +66716,7 @@ Examples:
|
|
|
67616
66716
|
});
|
|
67617
66717
|
|
|
67618
66718
|
// src/commands/studio/keep.ts
|
|
67619
|
-
import { defineCommand as
|
|
66719
|
+
import { defineCommand as defineCommand214 } from "citty";
|
|
67620
66720
|
registerSchema({
|
|
67621
66721
|
command: "studio.keep",
|
|
67622
66722
|
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.",
|
|
@@ -67626,7 +66726,7 @@ registerSchema({
|
|
|
67626
66726
|
undo: { type: "boolean", description: "Un-star an image, or take a kept clip back out", required: false }
|
|
67627
66727
|
}
|
|
67628
66728
|
});
|
|
67629
|
-
var keepCommand =
|
|
66729
|
+
var keepCommand = defineCommand214({
|
|
67630
66730
|
meta: {
|
|
67631
66731
|
name: "keep",
|
|
67632
66732
|
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"
|
|
@@ -67677,7 +66777,7 @@ var keepCommand = defineCommand215({
|
|
|
67677
66777
|
});
|
|
67678
66778
|
|
|
67679
66779
|
// src/commands/studio/list.ts
|
|
67680
|
-
import { defineCommand as
|
|
66780
|
+
import { defineCommand as defineCommand215 } from "citty";
|
|
67681
66781
|
registerSchema({
|
|
67682
66782
|
command: "studio.list",
|
|
67683
66783
|
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.",
|
|
@@ -67688,7 +66788,7 @@ registerSchema({
|
|
|
67688
66788
|
full: { type: "boolean", description: "Include settings, references and attribution", required: false }
|
|
67689
66789
|
}
|
|
67690
66790
|
});
|
|
67691
|
-
var listCommand18 =
|
|
66791
|
+
var listCommand18 = defineCommand215({
|
|
67692
66792
|
meta: {
|
|
67693
66793
|
name: "list",
|
|
67694
66794
|
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"
|
|
@@ -67722,7 +66822,7 @@ var listCommand18 = defineCommand216({
|
|
|
67722
66822
|
});
|
|
67723
66823
|
|
|
67724
66824
|
// src/commands/studio/models.ts
|
|
67725
|
-
import { defineCommand as
|
|
66825
|
+
import { defineCommand as defineCommand216 } from "citty";
|
|
67726
66826
|
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.";
|
|
67727
66827
|
registerSchema({
|
|
67728
66828
|
command: "studio.models",
|
|
@@ -67809,7 +66909,7 @@ function buildModelCards(kind, model) {
|
|
|
67809
66909
|
const selected = model ? ids.filter((id) => id === model) : ids;
|
|
67810
66910
|
return selected.map((id) => build(id));
|
|
67811
66911
|
}
|
|
67812
|
-
var modelsCommand =
|
|
66912
|
+
var modelsCommand = defineCommand216({
|
|
67813
66913
|
meta: {
|
|
67814
66914
|
name: "models",
|
|
67815
66915
|
description: `${DESCRIPTION3}
|
|
@@ -67856,13 +66956,13 @@ Examples:
|
|
|
67856
66956
|
});
|
|
67857
66957
|
|
|
67858
66958
|
// src/commands/studio/skills.ts
|
|
67859
|
-
import { defineCommand as
|
|
66959
|
+
import { defineCommand as defineCommand217 } from "citty";
|
|
67860
66960
|
registerSchema({
|
|
67861
66961
|
command: "studio.skills",
|
|
67862
66962
|
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.",
|
|
67863
66963
|
args: {}
|
|
67864
66964
|
});
|
|
67865
|
-
var skillsCommand =
|
|
66965
|
+
var skillsCommand = defineCommand217({
|
|
67866
66966
|
meta: {
|
|
67867
66967
|
name: "skills",
|
|
67868
66968
|
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"
|
|
@@ -67886,7 +66986,7 @@ var skillsCommand = defineCommand218({
|
|
|
67886
66986
|
});
|
|
67887
66987
|
|
|
67888
66988
|
// src/commands/studio/index.ts
|
|
67889
|
-
var studioCommand =
|
|
66989
|
+
var studioCommand = defineCommand218({
|
|
67890
66990
|
meta: {
|
|
67891
66991
|
name: "studio",
|
|
67892
66992
|
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.
|
|
@@ -67929,10 +67029,10 @@ Full guide: __tooling__/docs/tools/baker/studio.md`
|
|
|
67929
67029
|
});
|
|
67930
67030
|
|
|
67931
67031
|
// src/commands/tag-manager/index.ts
|
|
67932
|
-
import { defineCommand as
|
|
67032
|
+
import { defineCommand as defineCommand222 } from "citty";
|
|
67933
67033
|
|
|
67934
67034
|
// src/commands/tag-manager/draft.ts
|
|
67935
|
-
import { defineCommand as
|
|
67035
|
+
import { defineCommand as defineCommand219 } from "citty";
|
|
67936
67036
|
|
|
67937
67037
|
// src/commands/tag-manager/shared.ts
|
|
67938
67038
|
import { readFileSync as readFileSync20 } from "fs";
|
|
@@ -67948,21 +67048,21 @@ function requireTarget6(args5, entity) {
|
|
|
67948
67048
|
}
|
|
67949
67049
|
return target2;
|
|
67950
67050
|
}
|
|
67951
|
-
function loadJsonArg2(args5,
|
|
67952
|
-
const inline = args5[
|
|
67051
|
+
function loadJsonArg2(args5, flag2 = "json") {
|
|
67052
|
+
const inline = args5[flag2];
|
|
67953
67053
|
const file = args5.file;
|
|
67954
67054
|
const raw = typeof file === "string" && file.length > 0 ? readFileSync20(file, "utf8") : typeof inline === "string" && inline.length > 0 ? inline : void 0;
|
|
67955
67055
|
if (raw === void 0) {
|
|
67956
|
-
failValidation5(`pass --${
|
|
67056
|
+
failValidation5(`pass --${flag2} with inline JSON or --file with a path to a JSON file`);
|
|
67957
67057
|
}
|
|
67958
67058
|
try {
|
|
67959
67059
|
const parsed = JSON.parse(raw);
|
|
67960
67060
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
67961
|
-
failValidation5(`--${
|
|
67061
|
+
failValidation5(`--${flag2} must be a JSON object`);
|
|
67962
67062
|
}
|
|
67963
67063
|
return parsed;
|
|
67964
67064
|
} catch {
|
|
67965
|
-
return failValidation5(`--${
|
|
67065
|
+
return failValidation5(`--${flag2} is not valid JSON`);
|
|
67966
67066
|
}
|
|
67967
67067
|
}
|
|
67968
67068
|
var RETRYABLE_CODES2 = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
@@ -68055,13 +67155,13 @@ registerSchema({
|
|
|
68055
67155
|
chat: { type: "string", description: CHAT_READ_ARG.description, required: false }
|
|
68056
67156
|
}
|
|
68057
67157
|
});
|
|
68058
|
-
var draftCommand5 =
|
|
67158
|
+
var draftCommand5 = defineCommand219({
|
|
68059
67159
|
meta: {
|
|
68060
67160
|
name: "draft",
|
|
68061
67161
|
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."
|
|
68062
67162
|
},
|
|
68063
67163
|
subCommands: {
|
|
68064
|
-
list:
|
|
67164
|
+
list: defineCommand219({
|
|
68065
67165
|
meta: {
|
|
68066
67166
|
name: "list",
|
|
68067
67167
|
description: "Review everything staged on this chat (--json for the raw envelope)"
|
|
@@ -68074,7 +67174,7 @@ var draftCommand5 = defineCommand220({
|
|
|
68074
67174
|
await draftList2(args5.json === true, args5.chat);
|
|
68075
67175
|
}
|
|
68076
67176
|
}),
|
|
68077
|
-
show:
|
|
67177
|
+
show: defineCommand219({
|
|
68078
67178
|
meta: {
|
|
68079
67179
|
name: "show",
|
|
68080
67180
|
description: "Print the full staged payload for one change \u2014 the receipt to verify it looks right before publish (never truncated)."
|
|
@@ -68091,7 +67191,7 @@ var draftCommand5 = defineCommand220({
|
|
|
68091
67191
|
);
|
|
68092
67192
|
}
|
|
68093
67193
|
}),
|
|
68094
|
-
amend:
|
|
67194
|
+
amend: defineCommand219({
|
|
68095
67195
|
meta: {
|
|
68096
67196
|
name: "amend",
|
|
68097
67197
|
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."
|
|
@@ -68108,7 +67208,7 @@ var draftCommand5 = defineCommand220({
|
|
|
68108
67208
|
});
|
|
68109
67209
|
}
|
|
68110
67210
|
}),
|
|
68111
|
-
remove:
|
|
67211
|
+
remove: defineCommand219({
|
|
68112
67212
|
meta: { name: "remove", description: "Remove one staged change (cascades to anything depending on it)" },
|
|
68113
67213
|
args: { ref: { type: "positional", description: "Staged ref (gtm_temp_*) or target", required: false } },
|
|
68114
67214
|
run: async ({ args: args5 }) => {
|
|
@@ -68117,7 +67217,7 @@ var draftCommand5 = defineCommand220({
|
|
|
68117
67217
|
});
|
|
68118
67218
|
}
|
|
68119
67219
|
}),
|
|
68120
|
-
clear:
|
|
67220
|
+
clear: defineCommand219({
|
|
68121
67221
|
meta: { name: "clear", description: "Discard all Tag Manager changes staged on this chat" },
|
|
68122
67222
|
run: async () => {
|
|
68123
67223
|
await draftAction3("/api/tag-manager/draft/clear", {});
|
|
@@ -68127,7 +67227,7 @@ var draftCommand5 = defineCommand220({
|
|
|
68127
67227
|
});
|
|
68128
67228
|
|
|
68129
67229
|
// src/commands/tag-manager/read.ts
|
|
68130
|
-
import { defineCommand as
|
|
67230
|
+
import { defineCommand as defineCommand220 } from "citty";
|
|
68131
67231
|
registerSchema({
|
|
68132
67232
|
command: "tagManager.containers",
|
|
68133
67233
|
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.",
|
|
@@ -68168,7 +67268,7 @@ function containersHints(containers) {
|
|
|
68168
67268
|
}))
|
|
68169
67269
|
});
|
|
68170
67270
|
}
|
|
68171
|
-
var containersCommand =
|
|
67271
|
+
var containersCommand = defineCommand220({
|
|
68172
67272
|
meta: {
|
|
68173
67273
|
name: "containers",
|
|
68174
67274
|
description: `List Tag Manager containers reachable by this company's connection.
|
|
@@ -68185,7 +67285,7 @@ Start here:
|
|
|
68185
67285
|
}
|
|
68186
67286
|
}
|
|
68187
67287
|
});
|
|
68188
|
-
var readCommand =
|
|
67288
|
+
var readCommand = defineCommand220({
|
|
68189
67289
|
meta: {
|
|
68190
67290
|
name: "read",
|
|
68191
67291
|
description: `Read the current contents of the Tag Manager container \u2014 always do this before staging changes.
|
|
@@ -68227,7 +67327,7 @@ Examples:
|
|
|
68227
67327
|
});
|
|
68228
67328
|
|
|
68229
67329
|
// src/commands/tag-manager/write-commands.ts
|
|
68230
|
-
import { defineCommand as
|
|
67330
|
+
import { defineCommand as defineCommand221 } from "citty";
|
|
68231
67331
|
var CONTAINER_ARG_DESCRIPTION = "Numeric container id (optional only when one container is connected \u2014 run `baker tag-manager containers`)";
|
|
68232
67332
|
var ENTITIES = [
|
|
68233
67333
|
{
|
|
@@ -68283,10 +67383,10 @@ for (const { entity, noun, createHint } of ENTITIES) {
|
|
|
68283
67383
|
});
|
|
68284
67384
|
}
|
|
68285
67385
|
function entityCommand(entity, noun, example) {
|
|
68286
|
-
return
|
|
67386
|
+
return defineCommand221({
|
|
68287
67387
|
meta: { name: entity, description: `Stage ${noun} changes on this chat's Tag Manager draft` },
|
|
68288
67388
|
subCommands: {
|
|
68289
|
-
create:
|
|
67389
|
+
create: defineCommand221({
|
|
68290
67390
|
meta: {
|
|
68291
67391
|
name: "create",
|
|
68292
67392
|
description: `Stage a new ${noun}
|
|
@@ -68308,7 +67408,7 @@ Examples:
|
|
|
68308
67408
|
});
|
|
68309
67409
|
}
|
|
68310
67410
|
}),
|
|
68311
|
-
update:
|
|
67411
|
+
update: defineCommand221({
|
|
68312
67412
|
meta: {
|
|
68313
67413
|
name: "update",
|
|
68314
67414
|
description: `Stage an update to an existing ${noun} (pass its id or path)`
|
|
@@ -68328,7 +67428,7 @@ Examples:
|
|
|
68328
67428
|
});
|
|
68329
67429
|
}
|
|
68330
67430
|
}),
|
|
68331
|
-
delete:
|
|
67431
|
+
delete: defineCommand221({
|
|
68332
67432
|
meta: { name: "delete", description: `Stage the deletion of a ${noun} (pass its id or path)` },
|
|
68333
67433
|
args: {
|
|
68334
67434
|
id: { type: "positional", description: `${noun} id or path`, required: false },
|
|
@@ -68369,7 +67469,7 @@ function builtinTypes(args5) {
|
|
|
68369
67469
|
}
|
|
68370
67470
|
return raw.split(",").map((entry) => entry.trim());
|
|
68371
67471
|
}
|
|
68372
|
-
var builtinCommand =
|
|
67472
|
+
var builtinCommand = defineCommand221({
|
|
68373
67473
|
meta: {
|
|
68374
67474
|
name: "builtin",
|
|
68375
67475
|
description: `Enable or disable built-in variables
|
|
@@ -68379,7 +67479,7 @@ Examples:
|
|
|
68379
67479
|
baker tag-manager builtin disable --types formId`
|
|
68380
67480
|
},
|
|
68381
67481
|
subCommands: {
|
|
68382
|
-
enable:
|
|
67482
|
+
enable: defineCommand221({
|
|
68383
67483
|
meta: { name: "enable", description: "Stage enabling built-in variables" },
|
|
68384
67484
|
args: {
|
|
68385
67485
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -68393,7 +67493,7 @@ Examples:
|
|
|
68393
67493
|
});
|
|
68394
67494
|
}
|
|
68395
67495
|
}),
|
|
68396
|
-
disable:
|
|
67496
|
+
disable: defineCommand221({
|
|
68397
67497
|
meta: { name: "disable", description: "Stage disabling built-in variables" },
|
|
68398
67498
|
args: {
|
|
68399
67499
|
types: { type: "string", description: "Comma-separated types", required: false },
|
|
@@ -68411,7 +67511,7 @@ Examples:
|
|
|
68411
67511
|
});
|
|
68412
67512
|
|
|
68413
67513
|
// src/commands/tag-manager/index.ts
|
|
68414
|
-
var tagManagerCommand =
|
|
67514
|
+
var tagManagerCommand = defineCommand222({
|
|
68415
67515
|
meta: {
|
|
68416
67516
|
name: "tag-manager",
|
|
68417
67517
|
description: `Read and change what lives inside the client's Google Tag Manager container \u2014 tags, triggers, variables, folders and built-in variables.
|
|
@@ -68448,7 +67548,7 @@ Full guide: __tooling__/docs/tools/baker/tag-manager.md`
|
|
|
68448
67548
|
});
|
|
68449
67549
|
|
|
68450
67550
|
// src/commands/tags/index.ts
|
|
68451
|
-
import { defineCommand as
|
|
67551
|
+
import { defineCommand as defineCommand223 } from "citty";
|
|
68452
67552
|
|
|
68453
67553
|
// src/commands/tags/shared.ts
|
|
68454
67554
|
function failApi3(err) {
|
|
@@ -68528,7 +67628,7 @@ async function listTags(json) {
|
|
|
68528
67628
|
var listArgs11 = {
|
|
68529
67629
|
json: { type: "boolean", description: "Print the raw JSON envelope instead of the readable list" }
|
|
68530
67630
|
};
|
|
68531
|
-
var listCommand19 =
|
|
67631
|
+
var listCommand19 = defineCommand223({
|
|
68532
67632
|
meta: {
|
|
68533
67633
|
name: "list",
|
|
68534
67634
|
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"
|
|
@@ -68547,7 +67647,7 @@ async function listDraft4(chat) {
|
|
|
68547
67647
|
failApi3(err);
|
|
68548
67648
|
}
|
|
68549
67649
|
}
|
|
68550
|
-
var draftCommand6 =
|
|
67650
|
+
var draftCommand6 = defineCommand223({
|
|
68551
67651
|
meta: {
|
|
68552
67652
|
name: "draft",
|
|
68553
67653
|
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."
|
|
@@ -68557,7 +67657,7 @@ var draftCommand6 = defineCommand224({
|
|
|
68557
67657
|
await listDraft4(args5.chat);
|
|
68558
67658
|
}
|
|
68559
67659
|
});
|
|
68560
|
-
var tagsCommand4 =
|
|
67660
|
+
var tagsCommand4 = defineCommand223({
|
|
68561
67661
|
meta: {
|
|
68562
67662
|
name: "tags",
|
|
68563
67663
|
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.
|
|
@@ -68586,10 +67686,10 @@ Full guide: __tooling__/docs/tools/baker/tags.md`
|
|
|
68586
67686
|
});
|
|
68587
67687
|
|
|
68588
67688
|
// src/commands/testimonials/index.ts
|
|
68589
|
-
import { defineCommand as
|
|
67689
|
+
import { defineCommand as defineCommand227 } from "citty";
|
|
68590
67690
|
|
|
68591
67691
|
// src/commands/testimonials/get.ts
|
|
68592
|
-
import { defineCommand as
|
|
67692
|
+
import { defineCommand as defineCommand224 } from "citty";
|
|
68593
67693
|
registerSchema({
|
|
68594
67694
|
command: "testimonials.get",
|
|
68595
67695
|
description: "Get a single testimonial by ID",
|
|
@@ -68597,7 +67697,7 @@ registerSchema({
|
|
|
68597
67697
|
id: { type: "string", description: "Testimonial ID", required: true }
|
|
68598
67698
|
}
|
|
68599
67699
|
});
|
|
68600
|
-
var getCommand6 =
|
|
67700
|
+
var getCommand6 = defineCommand224({
|
|
68601
67701
|
meta: { name: "get", description: "Get a single testimonial by ID. Example: baker testimonials get j571abc123" },
|
|
68602
67702
|
args: {
|
|
68603
67703
|
id: { type: "positional", description: "Testimonial ID", required: false },
|
|
@@ -68634,7 +67734,7 @@ var getCommand6 = defineCommand225({
|
|
|
68634
67734
|
});
|
|
68635
67735
|
|
|
68636
67736
|
// src/commands/testimonials/list.ts
|
|
68637
|
-
import { defineCommand as
|
|
67737
|
+
import { defineCommand as defineCommand225 } from "citty";
|
|
68638
67738
|
|
|
68639
67739
|
// src/commands/testimonials/emptyCorpusHints.ts
|
|
68640
67740
|
function resolveEmptyReason({
|
|
@@ -68783,15 +67883,15 @@ var PARAM_NAMES = {
|
|
|
68783
67883
|
};
|
|
68784
67884
|
function buildListParams(args5) {
|
|
68785
67885
|
const params2 = {};
|
|
68786
|
-
for (const [
|
|
68787
|
-
const value = args5[
|
|
67886
|
+
for (const [flag2, param] of Object.entries(PARAM_NAMES)) {
|
|
67887
|
+
const value = args5[flag2];
|
|
68788
67888
|
if (value !== void 0 && value !== "") {
|
|
68789
67889
|
params2[param] = String(value);
|
|
68790
67890
|
}
|
|
68791
67891
|
}
|
|
68792
67892
|
return params2;
|
|
68793
67893
|
}
|
|
68794
|
-
var listCommand20 =
|
|
67894
|
+
var listCommand20 = defineCommand225({
|
|
68795
67895
|
meta: {
|
|
68796
67896
|
name: "list",
|
|
68797
67897
|
description: "List testimonials with optional filters. Example: baker testimonials list --source google --sentiment positive"
|
|
@@ -68851,7 +67951,7 @@ var listCommand20 = defineCommand226({
|
|
|
68851
67951
|
});
|
|
68852
67952
|
|
|
68853
67953
|
// src/commands/testimonials/search.ts
|
|
68854
|
-
import { defineCommand as
|
|
67954
|
+
import { defineCommand as defineCommand226 } from "citty";
|
|
68855
67955
|
var FILTER_FLAGS2 = ["source", "rating-min", "rating-max", "status", "sentiment", "language", "tags"];
|
|
68856
67956
|
function languageBiasHint(results, requestedLanguage) {
|
|
68857
67957
|
if (requestedLanguage) {
|
|
@@ -68930,7 +68030,7 @@ function buildSearchRequest(query, args5) {
|
|
|
68930
68030
|
}
|
|
68931
68031
|
return body;
|
|
68932
68032
|
}
|
|
68933
|
-
var searchCommand3 =
|
|
68033
|
+
var searchCommand3 = defineCommand226({
|
|
68934
68034
|
meta: {
|
|
68935
68035
|
name: "search",
|
|
68936
68036
|
description: "Semantic search testimonials by text query. Uses hybrid BM25 + vector + reranking. Example: baker testimonials search 'great service' --rating-min 4"
|
|
@@ -68994,7 +68094,7 @@ var searchCommand3 = defineCommand227({
|
|
|
68994
68094
|
var tagsCommand5 = makeTagsCommand("testimonials", "testimonial", "/api/testimonials/tags");
|
|
68995
68095
|
|
|
68996
68096
|
// src/commands/testimonials/index.ts
|
|
68997
|
-
var testimonialsCommand =
|
|
68097
|
+
var testimonialsCommand = defineCommand227({
|
|
68998
68098
|
meta: {
|
|
68999
68099
|
name: "testimonials",
|
|
69000
68100
|
description: `Find and browse testimonials in Baker. Subcommands: search, get, list, tags.
|
|
@@ -69016,10 +68116,10 @@ Full guide: __tooling__/docs/tools/baker/testimonials.md`
|
|
|
69016
68116
|
});
|
|
69017
68117
|
|
|
69018
68118
|
// src/commands/videos/index.ts
|
|
69019
|
-
import { defineCommand as
|
|
68119
|
+
import { defineCommand as defineCommand235 } from "citty";
|
|
69020
68120
|
|
|
69021
68121
|
// src/commands/videos/delete.ts
|
|
69022
|
-
import { defineCommand as
|
|
68122
|
+
import { defineCommand as defineCommand228 } from "citty";
|
|
69023
68123
|
registerSchema({
|
|
69024
68124
|
command: "videos.delete",
|
|
69025
68125
|
description: "Delete a video by ID",
|
|
@@ -69033,7 +68133,7 @@ registerSchema({
|
|
|
69033
68133
|
}
|
|
69034
68134
|
}
|
|
69035
68135
|
});
|
|
69036
|
-
var deleteCommand4 =
|
|
68136
|
+
var deleteCommand4 = defineCommand228({
|
|
69037
68137
|
meta: {
|
|
69038
68138
|
name: "delete",
|
|
69039
68139
|
description: "Delete a video by ID. Use --dry-run to preview. Example: baker videos delete j571abc123 --dry-run"
|
|
@@ -69074,7 +68174,7 @@ var deleteCommand4 = defineCommand229({
|
|
|
69074
68174
|
});
|
|
69075
68175
|
|
|
69076
68176
|
// src/commands/videos/describe.ts
|
|
69077
|
-
import { defineCommand as
|
|
68177
|
+
import { defineCommand as defineCommand229 } from "citty";
|
|
69078
68178
|
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.";
|
|
69079
68179
|
registerSchema({
|
|
69080
68180
|
command: "videos.describe",
|
|
@@ -69091,7 +68191,7 @@ registerSchema({
|
|
|
69091
68191
|
full: { type: "boolean", description: "Return the whole library row, not just what changed", required: false }
|
|
69092
68192
|
}
|
|
69093
68193
|
});
|
|
69094
|
-
var describeCommand2 =
|
|
68194
|
+
var describeCommand2 = defineCommand229({
|
|
69095
68195
|
meta: {
|
|
69096
68196
|
name: "describe",
|
|
69097
68197
|
description: `Correct what the library says a video is. Only the fields you pass change; the rest keep their current values.
|
|
@@ -69149,7 +68249,7 @@ Example: baker videos describe j571abc123 --description "Customer explaining how
|
|
|
69149
68249
|
});
|
|
69150
68250
|
|
|
69151
68251
|
// src/commands/videos/get.ts
|
|
69152
|
-
import { defineCommand as
|
|
68252
|
+
import { defineCommand as defineCommand230 } from "citty";
|
|
69153
68253
|
registerSchema({
|
|
69154
68254
|
command: "videos.get",
|
|
69155
68255
|
description: "Get a single video by ID",
|
|
@@ -69157,7 +68257,7 @@ registerSchema({
|
|
|
69157
68257
|
id: { type: "string", description: "Video ID", required: true }
|
|
69158
68258
|
}
|
|
69159
68259
|
});
|
|
69160
|
-
var getCommand7 =
|
|
68260
|
+
var getCommand7 = defineCommand230({
|
|
69161
68261
|
meta: { name: "get", description: "Get a single video by ID. Example: baker videos get j571abc123" },
|
|
69162
68262
|
args: {
|
|
69163
68263
|
id: { type: "positional", description: "Video ID", required: false },
|
|
@@ -69194,7 +68294,7 @@ var getCommand7 = defineCommand231({
|
|
|
69194
68294
|
});
|
|
69195
68295
|
|
|
69196
68296
|
// src/commands/videos/group.ts
|
|
69197
|
-
import { defineCommand as
|
|
68297
|
+
import { defineCommand as defineCommand231 } from "citty";
|
|
69198
68298
|
registerSchema({
|
|
69199
68299
|
command: "videos.group",
|
|
69200
68300
|
description: "List every clip and image that arrived in the same set as this video (carousel slides, one page)",
|
|
@@ -69203,7 +68303,7 @@ registerSchema({
|
|
|
69203
68303
|
"group-key": { type: "string", description: "The set key directly, when you already have it", required: false }
|
|
69204
68304
|
}
|
|
69205
68305
|
});
|
|
69206
|
-
var groupCommand2 =
|
|
68306
|
+
var groupCommand2 = defineCommand231({
|
|
69207
68307
|
meta: {
|
|
69208
68308
|
name: "group",
|
|
69209
68309
|
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>"
|
|
@@ -69226,7 +68326,7 @@ var groupCommand2 = defineCommand232({
|
|
|
69226
68326
|
import { mkdtemp as mkdtemp3, rm as rm9, stat as stat11 } from "fs/promises";
|
|
69227
68327
|
import { tmpdir as tmpdir4 } from "os";
|
|
69228
68328
|
import path47 from "path";
|
|
69229
|
-
import { defineCommand as
|
|
68329
|
+
import { defineCommand as defineCommand232 } from "citty";
|
|
69230
68330
|
|
|
69231
68331
|
// src/lib/streamUpload.ts
|
|
69232
68332
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -69390,7 +68490,7 @@ registerSchema({
|
|
|
69390
68490
|
"dry-run": { type: "boolean", description: "Preview the operation without executing", required: false }
|
|
69391
68491
|
}
|
|
69392
68492
|
});
|
|
69393
|
-
var ingestCommand2 =
|
|
68493
|
+
var ingestCommand2 = defineCommand232({
|
|
69394
68494
|
meta: {
|
|
69395
68495
|
name: "ingest",
|
|
69396
68496
|
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"
|
|
@@ -69652,7 +68752,7 @@ async function uploadToAssetStore(filePath, sizeBytes) {
|
|
|
69652
68752
|
}
|
|
69653
68753
|
|
|
69654
68754
|
// src/commands/videos/search.ts
|
|
69655
|
-
import { defineCommand as
|
|
68755
|
+
import { defineCommand as defineCommand233 } from "citty";
|
|
69656
68756
|
registerSchema({
|
|
69657
68757
|
command: "videos.search",
|
|
69658
68758
|
description: "Search videos by text query. Only returns ready videos.",
|
|
@@ -69662,7 +68762,7 @@ registerSchema({
|
|
|
69662
68762
|
tags: { type: "string", description: "Comma-separated tags to filter by", required: false }
|
|
69663
68763
|
}
|
|
69664
68764
|
});
|
|
69665
|
-
var searchCommand4 =
|
|
68765
|
+
var searchCommand4 = defineCommand233({
|
|
69666
68766
|
meta: {
|
|
69667
68767
|
name: "search",
|
|
69668
68768
|
description: "Semantic search videos by text query. Uses hybrid BM25 + vector + reranking. Example: baker videos search 'product demo' --tags tutorial"
|
|
@@ -69714,7 +68814,7 @@ var tagsCommand6 = makeTagsCommand("videos", "video", "/api/videos/tags");
|
|
|
69714
68814
|
// src/commands/videos/upload.ts
|
|
69715
68815
|
import { readFile as readFile33, stat as stat12 } from "fs/promises";
|
|
69716
68816
|
import { basename as basename3, extname as extname4 } from "path";
|
|
69717
|
-
import { defineCommand as
|
|
68817
|
+
import { defineCommand as defineCommand234 } from "citty";
|
|
69718
68818
|
var MIME_MAP = {
|
|
69719
68819
|
".mp4": "video/mp4",
|
|
69720
68820
|
".mov": "video/quicktime",
|
|
@@ -69756,7 +68856,7 @@ function detectContentType(filePath) {
|
|
|
69756
68856
|
function isRemoteUrl3(value) {
|
|
69757
68857
|
return /^https?:\/\//i.test(value);
|
|
69758
68858
|
}
|
|
69759
|
-
var uploadCommand2 =
|
|
68859
|
+
var uploadCommand2 = defineCommand234({
|
|
69760
68860
|
meta: {
|
|
69761
68861
|
name: "upload",
|
|
69762
68862
|
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"
|
|
@@ -69840,7 +68940,7 @@ var uploadCommand2 = defineCommand235({
|
|
|
69840
68940
|
});
|
|
69841
68941
|
|
|
69842
68942
|
// src/commands/videos/index.ts
|
|
69843
|
-
var videosCommand =
|
|
68943
|
+
var videosCommand = defineCommand235({
|
|
69844
68944
|
meta: {
|
|
69845
68945
|
name: "videos",
|
|
69846
68946
|
description: `Find and manage videos in Baker. Subcommands: search, get, upload, ingest, describe, delete, tags.
|
|
@@ -69869,10 +68969,10 @@ Full guide: __tooling__/docs/tools/baker/videos.md`
|
|
|
69869
68969
|
});
|
|
69870
68970
|
|
|
69871
68971
|
// src/commands/winning-ads/index.ts
|
|
69872
|
-
import { defineCommand as
|
|
68972
|
+
import { defineCommand as defineCommand248 } from "citty";
|
|
69873
68973
|
|
|
69874
68974
|
// src/commands/winning-ads/advertisers.ts
|
|
69875
|
-
import { defineCommand as
|
|
68975
|
+
import { defineCommand as defineCommand236 } from "citty";
|
|
69876
68976
|
|
|
69877
68977
|
// src/commands/winning-ads/shared.ts
|
|
69878
68978
|
function splitList3(value) {
|
|
@@ -69925,7 +69025,7 @@ function advertiserNormalizer(record, full) {
|
|
|
69925
69025
|
last_synced_at: record.last_synced_at ?? null
|
|
69926
69026
|
};
|
|
69927
69027
|
}
|
|
69928
|
-
var advertisersCommand2 =
|
|
69028
|
+
var advertisersCommand2 = defineCommand236({
|
|
69929
69029
|
meta: {
|
|
69930
69030
|
name: "advertisers",
|
|
69931
69031
|
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'
|
|
@@ -69983,7 +69083,7 @@ var advertisersCommand2 = defineCommand237({
|
|
|
69983
69083
|
});
|
|
69984
69084
|
|
|
69985
69085
|
// src/commands/winning-ads/brief.ts
|
|
69986
|
-
import { defineCommand as
|
|
69086
|
+
import { defineCommand as defineCommand237 } from "citty";
|
|
69987
69087
|
registerSchema({
|
|
69988
69088
|
command: "winning-ads.brief",
|
|
69989
69089
|
description: "Generate a creative brief grounded in strategically-similar winning ads. Optionally describe the target creative with --dna (JSON) and steer with --notes.",
|
|
@@ -70029,7 +69129,7 @@ function parseDna(raw) {
|
|
|
70029
69129
|
}
|
|
70030
69130
|
return parsed;
|
|
70031
69131
|
}
|
|
70032
|
-
var briefCommand =
|
|
69132
|
+
var briefCommand = defineCommand237({
|
|
70033
69133
|
meta: {
|
|
70034
69134
|
name: "brief",
|
|
70035
69135
|
description: `Generate a creative brief from winning references. Example: baker winning-ads brief --dna '{"angle":"cost savings"}' --notes "B2B, LinkedIn video" --k 8`
|
|
@@ -70065,7 +69165,7 @@ var briefCommand = defineCommand238({
|
|
|
70065
69165
|
});
|
|
70066
69166
|
|
|
70067
69167
|
// src/commands/winning-ads/content.ts
|
|
70068
|
-
import { defineCommand as
|
|
69168
|
+
import { defineCommand as defineCommand238 } from "citty";
|
|
70069
69169
|
registerSchema({
|
|
70070
69170
|
command: "winning-ads.content",
|
|
70071
69171
|
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.",
|
|
@@ -70078,7 +69178,7 @@ registerSchema({
|
|
|
70078
69178
|
}
|
|
70079
69179
|
}
|
|
70080
69180
|
});
|
|
70081
|
-
var contentCommand =
|
|
69181
|
+
var contentCommand = defineCommand238({
|
|
70082
69182
|
meta: {
|
|
70083
69183
|
name: "content",
|
|
70084
69184
|
description: "Read the transcript + on-screen text + copy of one winning ad. Example: baker winning-ads content adg_123 --platform meta --full --output md"
|
|
@@ -70127,7 +69227,7 @@ var contentCommand = defineCommand239({
|
|
|
70127
69227
|
});
|
|
70128
69228
|
|
|
70129
69229
|
// src/commands/winning-ads/feed.ts
|
|
70130
|
-
import { defineCommand as
|
|
69230
|
+
import { defineCommand as defineCommand239 } from "citty";
|
|
70131
69231
|
function buildFeedParams(input) {
|
|
70132
69232
|
const params2 = {};
|
|
70133
69233
|
const advertiser = splitList3(input.advertiser);
|
|
@@ -70179,7 +69279,7 @@ registerSchema({
|
|
|
70179
69279
|
format: { type: "string", description: "Comma-separated formats to include (e.g. static,video)", required: false }
|
|
70180
69280
|
}
|
|
70181
69281
|
});
|
|
70182
|
-
var feedCommand2 =
|
|
69282
|
+
var feedCommand2 = defineCommand239({
|
|
70183
69283
|
meta: {
|
|
70184
69284
|
name: "feed",
|
|
70185
69285
|
description: "Winners across every brand you follow (browse, then trim per advertiser). Example: baker winning-ads feed --per-advertiser 5 --output md"
|
|
@@ -70264,7 +69364,7 @@ var feedCommand2 = defineCommand240({
|
|
|
70264
69364
|
});
|
|
70265
69365
|
|
|
70266
69366
|
// src/commands/winning-ads/follow.ts
|
|
70267
|
-
import { defineCommand as
|
|
69367
|
+
import { defineCommand as defineCommand240 } from "citty";
|
|
70268
69368
|
var PLATFORMS = adLibraryPlatformSchema.options;
|
|
70269
69369
|
registerSchema({
|
|
70270
69370
|
command: "winning-ads.follow",
|
|
@@ -70279,7 +69379,7 @@ registerSchema({
|
|
|
70279
69379
|
label: { type: "string", description: "Optional display label (defaults to the resolved name)", required: false }
|
|
70280
69380
|
}
|
|
70281
69381
|
});
|
|
70282
|
-
var followCommand =
|
|
69382
|
+
var followCommand = defineCommand240({
|
|
70283
69383
|
meta: {
|
|
70284
69384
|
name: "follow",
|
|
70285
69385
|
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'
|
|
@@ -70326,7 +69426,7 @@ var followCommand = defineCommand241({
|
|
|
70326
69426
|
});
|
|
70327
69427
|
|
|
70328
69428
|
// src/commands/winning-ads/follow-competitors.ts
|
|
70329
|
-
import { defineCommand as
|
|
69429
|
+
import { defineCommand as defineCommand241 } from "citty";
|
|
70330
69430
|
var PLATFORMS2 = adLibraryPlatformSchema.options;
|
|
70331
69431
|
var BATCH_TIMEOUT_MS = 3e5;
|
|
70332
69432
|
function buildFollowBatchBody(input) {
|
|
@@ -70359,7 +69459,7 @@ registerSchema({
|
|
|
70359
69459
|
}
|
|
70360
69460
|
}
|
|
70361
69461
|
});
|
|
70362
|
-
var followCompetitorsCommand =
|
|
69462
|
+
var followCompetitorsCommand = defineCommand241({
|
|
70363
69463
|
meta: {
|
|
70364
69464
|
name: "follow-competitors",
|
|
70365
69465
|
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"'
|
|
@@ -70434,7 +69534,7 @@ var followCompetitorsCommand = defineCommand242({
|
|
|
70434
69534
|
});
|
|
70435
69535
|
|
|
70436
69536
|
// src/commands/winning-ads/following.ts
|
|
70437
|
-
import { defineCommand as
|
|
69537
|
+
import { defineCommand as defineCommand242 } from "citty";
|
|
70438
69538
|
registerSchema({
|
|
70439
69539
|
command: "winning-ads.following",
|
|
70440
69540
|
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.",
|
|
@@ -70488,7 +69588,7 @@ function followingNormalizer(record, full) {
|
|
|
70488
69588
|
platforms: Array.isArray(record.platforms) ? record.platforms : []
|
|
70489
69589
|
};
|
|
70490
69590
|
}
|
|
70491
|
-
var followingCommand =
|
|
69591
|
+
var followingCommand = defineCommand242({
|
|
70492
69592
|
meta: {
|
|
70493
69593
|
name: "following",
|
|
70494
69594
|
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"
|
|
@@ -70524,7 +69624,7 @@ var followingCommand = defineCommand243({
|
|
|
70524
69624
|
});
|
|
70525
69625
|
|
|
70526
69626
|
// src/commands/winning-ads/patterns.ts
|
|
70527
|
-
import { defineCommand as
|
|
69627
|
+
import { defineCommand as defineCommand243 } from "citty";
|
|
70528
69628
|
registerSchema({
|
|
70529
69629
|
command: "winning-ads.patterns",
|
|
70530
69630
|
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.",
|
|
@@ -70563,7 +69663,7 @@ function discriminatorRow(record) {
|
|
|
70563
69663
|
top_values_duds: Array.isArray(record.top_values_b) ? record.top_values_b.join(", ") : ""
|
|
70564
69664
|
};
|
|
70565
69665
|
}
|
|
70566
|
-
var patternsCommand =
|
|
69666
|
+
var patternsCommand = defineCommand243({
|
|
70567
69667
|
meta: {
|
|
70568
69668
|
name: "patterns",
|
|
70569
69669
|
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"
|
|
@@ -70619,7 +69719,7 @@ var patternsCommand = defineCommand244({
|
|
|
70619
69719
|
});
|
|
70620
69720
|
|
|
70621
69721
|
// src/commands/winning-ads/search.ts
|
|
70622
|
-
import { defineCommand as
|
|
69722
|
+
import { defineCommand as defineCommand244 } from "citty";
|
|
70623
69723
|
registerSchema({
|
|
70624
69724
|
command: "winning-ads.search",
|
|
70625
69725
|
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.",
|
|
@@ -70757,7 +69857,7 @@ function reportSearchError(err) {
|
|
|
70757
69857
|
}
|
|
70758
69858
|
reportError2(err);
|
|
70759
69859
|
}
|
|
70760
|
-
var searchCommand5 =
|
|
69860
|
+
var searchCommand5 = defineCommand244({
|
|
70761
69861
|
meta: {
|
|
70762
69862
|
name: "search",
|
|
70763
69863
|
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"
|
|
@@ -70877,7 +69977,7 @@ var searchCommand5 = defineCommand245({
|
|
|
70877
69977
|
});
|
|
70878
69978
|
|
|
70879
69979
|
// src/commands/winning-ads/seeds.ts
|
|
70880
|
-
import { defineCommand as
|
|
69980
|
+
import { defineCommand as defineCommand245 } from "citty";
|
|
70881
69981
|
function leanRow(r) {
|
|
70882
69982
|
return {
|
|
70883
69983
|
key: r.key,
|
|
@@ -70905,7 +70005,7 @@ function makeSeedCommand(opts) {
|
|
|
70905
70005
|
limit: { type: "number", description: "Max keys 1-100 (default 20)", required: false, default: 20 }
|
|
70906
70006
|
}
|
|
70907
70007
|
});
|
|
70908
|
-
return
|
|
70008
|
+
return defineCommand245({
|
|
70909
70009
|
meta: { name: opts.name, description: opts.description },
|
|
70910
70010
|
args: {
|
|
70911
70011
|
platform: { type: "string", description: "Single platform to segment on", required: false },
|
|
@@ -70954,7 +70054,7 @@ var formatsCommand = makeSeedCommand({
|
|
|
70954
70054
|
});
|
|
70955
70055
|
|
|
70956
70056
|
// src/commands/winning-ads/unfollow.ts
|
|
70957
|
-
import { defineCommand as
|
|
70057
|
+
import { defineCommand as defineCommand246 } from "citty";
|
|
70958
70058
|
registerSchema({
|
|
70959
70059
|
command: "winning-ads.unfollow",
|
|
70960
70060
|
description: "Stop following a brand \u2014 removes it from your ad-dna library by advertiser id.",
|
|
@@ -70962,7 +70062,7 @@ registerSchema({
|
|
|
70962
70062
|
advertiser: { type: "string", description: "Advertiser id to unfollow", required: true }
|
|
70963
70063
|
}
|
|
70964
70064
|
});
|
|
70965
|
-
var unfollowCommand =
|
|
70065
|
+
var unfollowCommand = defineCommand246({
|
|
70966
70066
|
meta: {
|
|
70967
70067
|
name: "unfollow",
|
|
70968
70068
|
description: "Stop following a brand by advertiser id. Example: baker winning-ads unfollow adv_123"
|
|
@@ -70983,7 +70083,7 @@ var unfollowCommand = defineCommand247({
|
|
|
70983
70083
|
});
|
|
70984
70084
|
|
|
70985
70085
|
// src/commands/winning-ads/winners.ts
|
|
70986
|
-
import { defineCommand as
|
|
70086
|
+
import { defineCommand as defineCommand247 } from "citty";
|
|
70987
70087
|
registerSchema({
|
|
70988
70088
|
command: "winning-ads.winners",
|
|
70989
70089
|
description: "Top winning ads for one advertiser id (from `advertisers` or `following`). Returns lean winner cards; add --full for DNA + longevity.",
|
|
@@ -70993,7 +70093,7 @@ registerSchema({
|
|
|
70993
70093
|
platform: { type: "string", description: "Filter to a single platform: meta|linkedin|tiktok", required: false }
|
|
70994
70094
|
}
|
|
70995
70095
|
});
|
|
70996
|
-
var winnersCommand =
|
|
70096
|
+
var winnersCommand = defineCommand247({
|
|
70997
70097
|
meta: {
|
|
70998
70098
|
name: "winners",
|
|
70999
70099
|
description: "Top winning ads for a specific advertiser id. Example: baker winning-ads winners adv_123 --top 15 --output md"
|
|
@@ -71043,7 +70143,7 @@ var winnersCommand = defineCommand248({
|
|
|
71043
70143
|
});
|
|
71044
70144
|
|
|
71045
70145
|
// src/commands/winning-ads/index.ts
|
|
71046
|
-
var winningAdsCommand =
|
|
70146
|
+
var winningAdsCommand = defineCommand248({
|
|
71047
70147
|
meta: {
|
|
71048
70148
|
name: "winning-ads",
|
|
71049
70149
|
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.
|
|
@@ -71235,16 +70335,16 @@ function commandFor(root, argv) {
|
|
|
71235
70335
|
return resolved ? command : null;
|
|
71236
70336
|
}
|
|
71237
70337
|
function suggestFlag(unknown, command) {
|
|
71238
|
-
const
|
|
71239
|
-
if (!
|
|
70338
|
+
const flag2 = closestFlag(unknown, command);
|
|
70339
|
+
if (!flag2) {
|
|
71240
70340
|
return null;
|
|
71241
70341
|
}
|
|
71242
70342
|
const args5 = argsOf(command) ?? {};
|
|
71243
|
-
const name =
|
|
70343
|
+
const name = flag2.slice(2);
|
|
71244
70344
|
const def = args5[name] ?? args5[camel(name)];
|
|
71245
70345
|
const described = def && typeof def === "object" ? def.description : void 0;
|
|
71246
70346
|
const description = typeof described === "string" ? described.split(/(?<!\b(?:e\.g|i\.e|vs))\.\s/)[0]?.trim().replace(/\.$/, "") : "";
|
|
71247
|
-
return description ? { flag:
|
|
70347
|
+
return description ? { flag: flag2, description } : { flag: flag2 };
|
|
71248
70348
|
}
|
|
71249
70349
|
function suggestionText(suggestion) {
|
|
71250
70350
|
if (!suggestion) {
|
|
@@ -71262,7 +70362,7 @@ function unknownFlagEnvelope(unknown, commandPath, suggestion, hasSchema) {
|
|
|
71262
70362
|
message: `${list} ${unknown.length > 1 ? "are not options" : "is not an option"} of \`baker ${commandPath}\`.`,
|
|
71263
70363
|
fix: {
|
|
71264
70364
|
action: hasSchema ? "check_schema" : "check_help",
|
|
71265
|
-
explanation: (unknown.some((
|
|
70365
|
+
explanation: (unknown.some((flag2) => flag2 === "--output" || flag2.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.`
|
|
71266
70366
|
},
|
|
71267
70367
|
retryable: false
|
|
71268
70368
|
}
|
|
@@ -71320,13 +70420,13 @@ function declaredArg(command, name) {
|
|
|
71320
70420
|
}
|
|
71321
70421
|
function envelopeRequests(argv) {
|
|
71322
70422
|
const end = argv.indexOf("--");
|
|
71323
|
-
const
|
|
70423
|
+
const limit = end === -1 ? argv.length : end;
|
|
71324
70424
|
const found = [];
|
|
71325
|
-
for (let index = 0; index <
|
|
70425
|
+
for (let index = 0; index < limit; index++) {
|
|
71326
70426
|
const token = argv[index];
|
|
71327
70427
|
if (token === `${FLAG}=${ENVELOPE}`) {
|
|
71328
70428
|
found.push({ index, length: 1 });
|
|
71329
|
-
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 <
|
|
70429
|
+
} else if (token === FLAG && argv[index + 1] === ENVELOPE && index + 1 < limit) {
|
|
71330
70430
|
found.push({ index, length: 2 });
|
|
71331
70431
|
index++;
|
|
71332
70432
|
}
|
|
@@ -71370,7 +70470,7 @@ function getCliVersion() {
|
|
|
71370
70470
|
}
|
|
71371
70471
|
|
|
71372
70472
|
// src/cli.ts
|
|
71373
|
-
var main =
|
|
70473
|
+
var main = defineCommand249({
|
|
71374
70474
|
meta: {
|
|
71375
70475
|
name: "baker",
|
|
71376
70476
|
version: getCliVersion(),
|