@wrangled/cli 0.3.42 → 0.3.43
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/dist/guide.js +1 -1
- package/dist/main.js +17 -8
- package/dist/playbooks.js +1 -1
- package/package.json +1 -1
package/dist/guide.js
CHANGED
|
@@ -301,7 +301,7 @@ ${cli} brief [--from <date>] [--to <date>] [--channel <channel>] [--campaign <id
|
|
|
301
301
|
${cli} pages brief --step <key> [--funnel <key>] | --page <ref> the offer, step, current page, best and worst pages of its kind, its ads and how to hand a page back: start here before writing a landing page
|
|
302
302
|
${cli} pages results [--from <date>] [--to <date>] [--page <ref>] each landing page's, and each ad and page pair's, real first-touch sales, cost per sale and sales per page view
|
|
303
303
|
${cli} messages results [--from <date>] [--to <date>] [--channel email|text] [--sequence <id>] real sales after each follow-up email, text and sequence: every message the buyer clicked or replied to in the ${MESSAGE_CREDIT_DAYS} days before buying (helped), and the latest one (last nudge)
|
|
304
|
-
${cli} winners [--week <date> | --days <n> | --from <date> --to <date>] [--top <n>] [--ad-format image|video|carousel] which Facebook ads and landing pages won and flopped in a week or any dates and over 30 days, judged on first-touch sales
|
|
304
|
+
${cli} winners [--week <date> | --days <n> | --from <date> --to <date>] [--top <n>] [--ad-format image|video|carousel] which Facebook ads and landing pages won and flopped in a week or any dates and over 30 days, judged on first-touch sales, or on Triple Whale's orders for a shop that has them
|
|
305
305
|
${cli} winners send-to-exodus [--week <date> | --days <n> | --from <date> --to <date>] [--dry-run] send the winners, with their reasons, lessons and customer words, to Exodus; safe to send again
|
|
306
306
|
${cli} warehouse schema [--summary] [--table <name> ...] [--search <words>] list tables and columns; --summary for one row per table
|
|
307
307
|
${cli} warehouse query "<sql>" run one read-only query (or --file <path>, or stdin); --out <file.csv | file.ndjson | file.json> saves the rows; add --all for every row
|
package/dist/main.js
CHANGED
|
@@ -681,7 +681,7 @@ const commands = {
|
|
|
681
681
|
},
|
|
682
682
|
},
|
|
683
683
|
winners: {
|
|
684
|
-
usage: "winners [--week <YYYY-MM-DD> | --days <n> | --from <YYYY-MM-DD> --to <YYYY-MM-DD>] [--top <n>] [--ad-format image|video|carousel] (which Facebook ads and landing pages won and flopped, judged on real first-touch
|
|
684
|
+
usage: "winners [--week <YYYY-MM-DD> | --days <n> | --from <YYYY-MM-DD> --to <YYYY-MM-DD>] [--top <n>] [--ad-format image|video|carousel] (which Facebook ads and landing pages won and flopped, judged on real sales: first-touch, or Triple Whale's orders when the workspace has them)",
|
|
685
685
|
async run(args, options) {
|
|
686
686
|
if (args.length > 0)
|
|
687
687
|
throw new CliError("Usage: winners [--week <date> | --days <n> | --from <date> --to <date>] [--top <n>] [--ad-format image|video|carousel]", exitCodes.usage);
|
|
@@ -2068,7 +2068,9 @@ function money(value, currency) {
|
|
|
2068
2068
|
return `${value.toFixed(2)} ${currency}`;
|
|
2069
2069
|
}
|
|
2070
2070
|
}
|
|
2071
|
-
|
|
2071
|
+
/** A model that splits credit between ads gives fractional counts: show tenths at most, grouped as the server writes them. */
|
|
2072
|
+
const tenths = (n) => n.toLocaleString("en-US", { maximumFractionDigits: 1 });
|
|
2073
|
+
const counted = (n, one) => `${tenths(n)} ${tenths(n) === "1" ? one : `${one}s`}`;
|
|
2072
2074
|
/** An ad's line: name, SKU and campaign, its numbers, its tags, then why it is on the list. */
|
|
2073
2075
|
function winnersAdLines(ad, currency) {
|
|
2074
2076
|
const n = ad.numbers;
|
|
@@ -2079,7 +2081,8 @@ function winnersAdLines(ad, currency) {
|
|
|
2079
2081
|
const name = [ad.name ?? `Ad ${ad.adId}`, ad.sku && `[${ad.sku}]`, ad.campaignName && `(${ad.campaignName})`].filter(Boolean).join(" ");
|
|
2080
2082
|
const tags = Object.entries(ad.tags).map(([field, value]) => `${field}: ${value}`).join(", ");
|
|
2081
2083
|
const count = onSales ? n.sales !== null && counted(n.sales, "sale") : n.signups !== null && counted(n.signups, "first lead");
|
|
2082
|
-
|
|
2084
|
+
const facebook = n.facebookResults == null ? "" : `, Facebook counts ${tenths(n.facebookResults)}`;
|
|
2085
|
+
return `- ${name}: spent ${money(n.spend, currency)}, ${count ? `${count}, ` : ""}${cost}${facebook}${tags ? `. Tags: ${tags}` : ""}\n ${ad.pickedBecause}\n`;
|
|
2083
2086
|
}
|
|
2084
2087
|
/** A page's or pair's line: the ad for a pair, the page, its visits and numbers, then why it is on the list. */
|
|
2085
2088
|
function winnersPageLines(page, currency) {
|
|
@@ -2117,7 +2120,7 @@ function winnersWindowText(title, window) {
|
|
|
2117
2120
|
: s.accountCostPerSale === null
|
|
2118
2121
|
? "no sale credited to a Facebook ad in these dates"
|
|
2119
2122
|
: `the account paid ${money(s.accountCostPerSale, s.currency)} per sale`;
|
|
2120
|
-
const tied = s.adSales === null || !s.facebookSales ? "" : ` ${s.adSales} of ${counted(s.facebookSales, "Facebook sale")} could be tied to a specific ad.`;
|
|
2123
|
+
const tied = s.adSales === null || !s.facebookSales ? "" : ` ${tenths(s.adSales)} of ${counted(s.facebookSales, "Facebook sale")} could be tied to a specific ad.`;
|
|
2121
2124
|
const tests = s.tests.map((t) => `- Test ${t.testId}${t.hypothesisId ? ` (idea ${t.hypothesisId})` : ""}: ${counted(t.ads.length, "ad")}, spent ${money(t.spend, s.currency)}, ${counted(t.sales, "sale")}` +
|
|
2122
2125
|
`${t.costPerSale === null ? "" : `, ${money(t.costPerSale, s.currency)} per sale`}\n`);
|
|
2123
2126
|
return (`\nIn ${s.currency}: ${account}.${tied} ${s.adsJudgedOnSales} judged on sales, ${s.adsJudgedOnSignups} judged on first leads.\n` +
|
|
@@ -2170,12 +2173,18 @@ function winnersSendText(sent) {
|
|
|
2170
2173
|
lines.push("Left out:", ...sent.skipped.map((s) => ` ${s.adId}: ${s.reason}`));
|
|
2171
2174
|
return `${lines.join("\n")}\n`;
|
|
2172
2175
|
}
|
|
2173
|
-
/**
|
|
2176
|
+
/** How an older server, which sent no rule, credited a sale. */
|
|
2177
|
+
const FIRST_TOUCH_SALE_RULE = "Each sale goes to the Facebook ad that first brought the buyer in; payments typed into GoHighLevel by hand never count toward an ad.";
|
|
2178
|
+
/**
|
|
2179
|
+
* The winners report as plain Markdown: what a sale means, then the dates asked for and, unless they are the same dates,
|
|
2180
|
+
* the last 30 days, each currency apart.
|
|
2181
|
+
*/
|
|
2174
2182
|
function winnersText(report) {
|
|
2183
|
+
const { week, last30Days } = report;
|
|
2175
2184
|
return (`# Winners and flops for ${report.workspace}${report.format ? `, ${report.format} ads only` : ""}\n\n` +
|
|
2176
|
-
`A sale means ${report.saleMeans}.
|
|
2177
|
-
winnersWindowText(winnersDatesTitle(report.window),
|
|
2178
|
-
winnersWindowText(`Last 30 days, ${
|
|
2185
|
+
`A sale means ${report.saleMeans}. ${report.saleRule ?? FIRST_TOUCH_SALE_RULE}\n` +
|
|
2186
|
+
winnersWindowText(winnersDatesTitle(report.window), week) +
|
|
2187
|
+
(week.from === last30Days.from && week.to === last30Days.to ? "" : winnersWindowText(`Last 30 days, ${last30Days.from} to ${last30Days.to}`, last30Days)));
|
|
2179
2188
|
}
|
|
2180
2189
|
function reportQuery(options, extra) {
|
|
2181
2190
|
const query = new URLSearchParams();
|
package/dist/playbooks.js
CHANGED
|
@@ -1564,7 +1564,7 @@ const testResultsSql = "SELECT test_id, currency, sum(spend) AS spend, sum(sales
|
|
|
1564
1564
|
const lineageSql = "SELECT facebook_ad_id, hypothesis_id, test_id, creative_id, asset_version FROM adzara_ad_lineage ORDER BY synced_at DESC LIMIT 100";
|
|
1565
1565
|
/** The commands the weekly loop shows, in order; its text is made from them, so a test runs exactly these. */
|
|
1566
1566
|
export const weeklyLoopCommands = {
|
|
1567
|
-
winners: { purpose: "the Facebook winners and flops of the dates asked for, here a week, and of the 30 days ending on their last day, judged on real first-touch
|
|
1567
|
+
winners: { purpose: "the Facebook winners and flops of the dates asked for, here a week, and of the 30 days ending on their last day, judged on real sales (first-touch, or Triple Whale's orders when the workspace has them)", argv: ["winners", "--week", "<week-monday>", "--format", "json"], mcp: "get_winners_report" },
|
|
1568
1568
|
lessons: { purpose: "what earlier weeks taught, the most often seen first", argv: ["lessons", "--format", "json"], mcp: "get_lessons" },
|
|
1569
1569
|
writeLessons: { purpose: "install the lessons playbook, then follow it to add, reinforce or retire this week's lessons", argv: ["skill", "install", "lessons"], mcp: "record_lesson" },
|
|
1570
1570
|
voice: { purpose: "fresh customer words: the most usable single lines said since that Monday", argv: ["voice", "--since", "<week-monday>", "--sort", "useful", "--json"], mcp: "get_customer_voice" },
|