@wrangled/cli 0.3.161 → 0.3.162
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 +2 -2
- package/dist/main.js +10 -5
- package/dist/playbooks.js +2 -2
- package/package.json +1 -1
package/dist/guide.js
CHANGED
|
@@ -324,7 +324,7 @@ Some clients review every batch before it goes out. \`${cli} review settings\` s
|
|
|
324
324
|
|
|
325
325
|
Each workspace keeps one map of what the client sells (the offer stack) and the steps a person walks from first seeing an ad to buying (its funnels). \`${cli} funnels show\` prints it in plain words: the version and who confirmed it, each offer in stack order with its tier, price and delivery, then each funnel's numbered steps with the offer it sells, its assets (marked \`(not found)\` when the id is not in synced data yet) and what counts as reaching it. It ends with the draft on hold, if any, printed in full. \`--version <n>\` prints an older version; \`--format json\` prints the whole map, which is the shape a draft takes.
|
|
326
326
|
|
|
327
|
-
To change the map, write the whole map as JSON (\`{"offers": [...], "funnels": [...]}\`, the \`map\` of \`${cli} funnels show --format json\`) and run \`${cli} funnels draft --file map.json --note "<what changed and why>"\`. Add \`--evidence '<json>'\` or \`@file.json\` with what you looked at: counts and ids, never names, emails or phones. It is checked against synced data, and when every step's rule is filled in it goes live at once, confirmed by \`system:auto\`; a person can undo it in the app. A map with a rule not filled in stays on hold as the draft and counts nothing; saving replaces the draft on hold. Never invent an id or a number to fill a rule. Pass \`--based-on <n>\` with the version you read (the draft on hold, else the confirmed map): if someone saved since, the save is refused as \`draft_conflict\`, and you show again and redo your change on top. Leave out \`--based-on\` only for the first map, when there is neither a map nor a draft; once there is one, a save without it is refused as \`draft_conflict\`. A map that does not fit is refused with every problem by path, such as \`funnels[0].steps[1].offer_key: no offer has the key x\`. Saving prints whether the map went live, what is left to fill in (an asset not synced yet, a rule with no calendar chosen), and the parts synced data does not back up, such as an offer with fewer than 3 buyers in a year. Because a save can change the client's numbers at once, run it first with \`--dry-run\`: that saves nothing and prints what saving would do (the version it would make, whether it would go live or wait on hold and why, the problems, warnings and questions), and refuses a stale \`--based-on\` the same way. When you are unsure the map is right, save with \`--hold\`: it is kept as the draft on hold, counting nothing, until a person puts it live in the app. \`--dry-run\` and \`--hold\` cannot be used together.
|
|
327
|
+
To change the map, write the whole map as JSON (\`{"offers": [...], "funnels": [...]}\`, the \`map\` of \`${cli} funnels show --format json\`) and run \`${cli} funnels draft --file map.json --note "<what changed and why>"\`. For a small change, send only the change instead: \`--patch '<json>'\` or \`@patch.json\` with JSON Patch ops on the version you read, named by key, such as \`[{"op": "replace", "path": "/offers/course/price", "value": 997}]\`, and \`--based-on\` that version; the patched map is checked and saved the same way, and an op that no longer applies is refused as \`patch_not_applicable\`. Add \`--evidence '<json>'\` or \`@file.json\` with what you looked at: counts and ids, never names, emails or phones. It is checked against synced data, and when every step's rule is filled in it goes live at once, confirmed by \`system:auto\`; a person can undo it in the app. A map with a rule not filled in stays on hold as the draft and counts nothing; saving replaces the draft on hold. Never invent an id or a number to fill a rule. Pass \`--based-on <n>\` with the version you read (the draft on hold, else the confirmed map): if someone saved since, the save is refused as \`draft_conflict\`, and you show again and redo your change on top. Leave out \`--based-on\` only for the first map, when there is neither a map nor a draft; once there is one, a save without it is refused as \`draft_conflict\`. A map that does not fit is refused with every problem by path, such as \`funnels[0].steps[1].offer_key: no offer has the key x\`. Saving prints whether the map went live, what is left to fill in (an asset not synced yet, a rule with no calendar chosen), and the parts synced data does not back up, such as an offer with fewer than 3 buyers in a year. Because a save can change the client's numbers at once, run it first with \`--dry-run\`: that saves nothing and prints what saving would do (the version it would make, whether it would go live or wait on hold and why, the problems, warnings and questions), and refuses a stale \`--based-on\` the same way. When you are unsure the map is right, save with \`--hold\`: it is kept as the draft on hold, counting nothing, until a person puts it live in the app. \`--dry-run\` and \`--hold\` cannot be used together.
|
|
328
328
|
|
|
329
329
|
\`--counts-from fix\` (the default) makes the map count for every past date the current map counted, as a fix; \`--counts-from <YYYY-MM-DD>\` makes it a change in the business that counts from that day (today or earlier). Save a fix and a change as two drafts, the fix first. \`--questions @questions.json\` asks a person what only they can settle: an array of \`{question_id, text, kind, evidence, options: [{label, patch}], default_option}\`, where the map already holds the default option and each other option's patch is JSON Patch ops on the map, naming offers, funnels and steps by key (\`/offers/course/matches/-\`). A question whose options all count the same sales and people, or that was answered already, is left out; at most 7 stay open, biggest money at stake first, and the checks add a yes/no question for each weak part no question covers. People answer them in the app; an answer saves the map as a fix, and later drafts keep it. \`${cli} funnels show\` lists the open and answered questions and says whether the map counts as a fix or from a date.
|
|
330
330
|
|
|
@@ -566,7 +566,7 @@ ${cli} funnels show [--version <n>] | funnels versions [--diff <a> <b>] the of
|
|
|
566
566
|
${cli} funnels numbers [--funnel <key>] [--from <date>] [--to <date>] how many reached each funnel step and moved on
|
|
567
567
|
${cli} funnels leaks [--funnel <key>] [--to <date>] the steps doing worse than their normal, costliest first
|
|
568
568
|
${cli} funnels evidence prices paid, buyer paths, GoHighLevel funnels, calendars and tags, webinars, pages and campaigns, to draft the map from
|
|
569
|
-
${cli} funnels draft --file <map.json> [--note <why>] [--evidence '<json>' | @file.json] [--based-on <n>] [--counts-from fix|<date>] [--questions @file.json] [--dry-run | --hold] save the whole map; it goes live when every step can be counted, unless --hold keeps it for a person; --dry-run saves nothing and says what saving would do
|
|
569
|
+
${cli} funnels draft --file <map.json> | --patch @patch.json [--note <why>] [--evidence '<json>' | @file.json] [--based-on <n>] [--counts-from fix|<date>] [--questions @file.json] [--dry-run | --hold] save the whole map, or a patch on version --based-on; it goes live when every step can be counted, unless --hold keeps it for a person; --dry-run saves nothing and says what saving would do
|
|
570
570
|
${cli} facts [--kind <kind>] [--subject <type>[:<ref>]] [--status <status>] [--json] | facts show <id> settled facts about the data, to treat as true
|
|
571
571
|
${cli} number-alerts [--since <date>] the key numbers that swung far from normal, day by day
|
|
572
572
|
${cli} facts propose --file <fact.json> suggest a fact for a person to confirm
|
package/dist/main.js
CHANGED
|
@@ -2819,22 +2819,24 @@ const commands = {
|
|
|
2819
2819
|
},
|
|
2820
2820
|
},
|
|
2821
2821
|
"funnels draft": {
|
|
2822
|
-
usage: "funnels draft --file <map.json> [--note <why>] [--evidence '<json>' | @file.json] [--based-on <n>] [--counts-from fix|<YYYY-MM-DD>] [--questions '<json>' | @file.json] [--dry-run | --hold] save a whole map; it counts at once when every step can be counted, unless --hold; --dry-run saves nothing and says what saving would do",
|
|
2822
|
+
usage: "funnels draft --file <map.json> | --patch '<json>' | @patch.json [--note <why>] [--evidence '<json>' | @file.json] [--based-on <n>] [--counts-from fix|<YYYY-MM-DD>] [--questions '<json>' | @file.json] [--dry-run | --hold] save a whole map, or a patch on version --based-on; it counts at once when every step can be counted, unless --hold; --dry-run saves nothing and says what saving would do",
|
|
2823
2823
|
async run(args, options) {
|
|
2824
|
-
const usage = "Usage: funnels draft --file <map.json> [--note <why>] [--evidence '<json>' | @file.json] [--based-on <n>] [--counts-from fix|<YYYY-MM-DD>] [--questions '<json>' | @file.json] [--dry-run | --hold]";
|
|
2825
|
-
if (args.length > 0 ||
|
|
2824
|
+
const usage = "Usage: funnels draft --file <map.json> | --patch '<json>' | @patch.json [--note <why>] [--evidence '<json>' | @file.json] [--based-on <n>] [--counts-from fix|<YYYY-MM-DD>] [--questions '<json>' | @file.json] [--dry-run | --hold]";
|
|
2825
|
+
if (args.length > 0 || Boolean(options.file) === (options.patch !== undefined))
|
|
2826
2826
|
throw new CliError(usage, exitCodes.usage);
|
|
2827
|
+
if (options.patch !== undefined && options.basedOn === undefined)
|
|
2828
|
+
throw new CliError("--patch needs --based-on: the version it changes.", exitCodes.usage);
|
|
2827
2829
|
if (options.dryRun && options.hold)
|
|
2828
2830
|
throw new CliError("Give --dry-run or --hold, not both: --dry-run saves nothing, --hold saves the map on hold.", exitCodes.usage);
|
|
2829
2831
|
if (options.countsFrom !== undefined && options.countsFrom !== "fix" && !/^\d{4}-\d{2}-\d{2}$/.test(options.countsFrom)) {
|
|
2830
2832
|
throw new CliError("--counts-from is fix or a date, YYYY-MM-DD", exitCodes.usage);
|
|
2831
2833
|
}
|
|
2832
|
-
const
|
|
2834
|
+
const change = options.patch === undefined ? { map: await parseJson(`@${options.file}`, "--file") } : { patch: await parseJson(options.patch, "--patch") };
|
|
2833
2835
|
const evidence = options.evidence === undefined ? undefined : await parseJson(options.evidence, "--evidence");
|
|
2834
2836
|
const questions = options.questions === undefined ? undefined : await parseJson(options.questions, "--questions");
|
|
2835
2837
|
const connection = await resolveConnection(options);
|
|
2836
2838
|
const basedOn = options.basedOn === undefined ? null : wholeNumber(options.basedOn, "--based-on");
|
|
2837
|
-
const saved = await api(connection, `${FUNNELS_PATH}/draft`, {
|
|
2839
|
+
const saved = await api(connection, `${FUNNELS_PATH}/draft`, { ...change, note: options.note, evidence, based_on: basedOn, counts_from: options.countsFrom, questions, apply: options.dryRun ? "check" : options.hold ? "hold" : "auto" }, "PUT");
|
|
2838
2840
|
if (options.format === "json")
|
|
2839
2841
|
return printJson(saved);
|
|
2840
2842
|
const based = basedOn === null ? "" : `, based on version ${basedOn}`;
|
|
@@ -5207,6 +5209,7 @@ Options:
|
|
|
5207
5209
|
--counts-from fix|<YYYY-MM-DD> how funnels draft counts: fix (default) for past dates too, or a change from that day
|
|
5208
5210
|
--questions <json | @file.json> the questions funnels draft asks a person, as an array; with map, no value: only
|
|
5209
5211
|
whether each everyday question can be answered
|
|
5212
|
+
--patch <json | @file.json> funnels draft: JSON Patch ops on version --based-on, instead of a whole map in --file
|
|
5210
5213
|
--person <name> with profile confirm, the name of the person in the chat who gave the answer
|
|
5211
5214
|
--diff <a> <b> with funnels versions, what changed from version a to version b
|
|
5212
5215
|
--funnel <key> only this funnel's steps in funnels numbers and funnels leaks (default: every funnel in the confirmed map);
|
|
@@ -5459,6 +5462,7 @@ function parseOptions(argv) {
|
|
|
5459
5462
|
evidence: { type: "string" },
|
|
5460
5463
|
"counts-from": { type: "string" },
|
|
5461
5464
|
questions: { type: "string" },
|
|
5465
|
+
patch: { type: "string" },
|
|
5462
5466
|
person: { type: "string" },
|
|
5463
5467
|
about: { type: "string" },
|
|
5464
5468
|
dimension: { type: "string", multiple: true },
|
|
@@ -5689,6 +5693,7 @@ function parseOptions(argv) {
|
|
|
5689
5693
|
evidence: values.evidence,
|
|
5690
5694
|
countsFrom: values["counts-from"],
|
|
5691
5695
|
questions: values.questions,
|
|
5696
|
+
patch: values.patch,
|
|
5692
5697
|
person: values.person,
|
|
5693
5698
|
about: values.about,
|
|
5694
5699
|
dimension: values.dimension,
|
package/dist/playbooks.js
CHANGED
|
@@ -701,8 +701,8 @@ Without a shell: MCP \`get_funnel_evidence\`, then MCP \`get_funnel_map\`.
|
|
|
701
701
|
|
|
702
702
|
\`evidence.json\` is \`{"evidence": {...}, "text": "..."}\`. The parts below are under \`.evidence\`, each either \`{"status": "ok", "rows": [...]}\` or \`{"status": "not_connected", "note": "..."}\`. Amounts are in whole currency units (1500 is 1,500.00), over the last \`.evidence.windowDays\` days unless a part says otherwise.
|
|
703
703
|
|
|
704
|
-
- **prices**: the prices people pay, on each platform, with how many buyers and payments. A GoHighLevel or Shopify row has the product's \`name\`, a Kajabi row the offer's title, with the Kajabi offer id as \`productId\`; a Stripe charge has none. For GoHighLevel, \`payments\` counts orders, not instalments. A GoHighLevel or Kajabi sale taken through Stripe shows twice, as a row naming the product and a Stripe row with only the amount, and the two amounts can differ a little (1497 and 1500).
|
|
705
|
-
- **buyerPaths**: the most common orders in which one person paid, with the median days between each payment. A small payment minutes after a big one is an order bump or upsell; a large payment weeks later is a back-end offer. A path such as \`[1500, 497, 3500]\` with medians \`[0, 60]\` reads: course, then an upsell the same day, then an event about two months later. A GoHighLevel checkout with an order bump is one payment of both prices together: 1994 is 1497 + 497. Before you take an amount for a new offer, check whether it is a sum of prices you already know.
|
|
704
|
+
- **prices**: the prices people pay, on each platform, with how many buyers and payments. A GoHighLevel or Shopify row has the product's \`name\`, a Kajabi row the offer's title, with the Kajabi offer id as \`productId\`; a Stripe charge has none. For GoHighLevel, \`payments\` counts orders, not instalments. A GoHighLevel payment with no order lines, such as an invoice, has only its amount, like a Stripe charge; match it with a \`ghl\` \`amount\` match. A GoHighLevel or Kajabi sale taken through Stripe shows twice, as a row naming the product and a Stripe row with only the amount, and the two amounts can differ a little (1497 and 1500).
|
|
705
|
+
- **buyerPaths**: the most common orders in which one person paid, with the median days between each payment. A path needs at least two payments by one person matched to a known person, so it is empty when no matched buyer paid twice in the window, even when prices has rows. A small payment minutes after a big one is an order bump or upsell; a large payment weeks later is a back-end offer. A path such as \`[1500, 497, 3500]\` with medians \`[0, 60]\` reads: course, then an upsell the same day, then an event about two months later. A GoHighLevel checkout with an order bump is one payment of both prices together: 1994 is 1497 + 497. Before you take an amount for a new offer, check whether it is a sum of prices you already know.
|
|
706
706
|
- **funnels**, **calendars**, **tags**: what GoHighLevel holds. Tags often name purchases and memberships.
|
|
707
707
|
- **pipelineStages**: each stage of the sales pipelines in GoHighLevel, HubSpot and Attio (\`source\` is \`ghl\`, \`hubspot\` or \`attio\`; \`accountId\` is the GoHighLevel location id, the HubSpot account id or the Attio workspace id), with the deals in it now and, for GoHighLevel only, how many moved into it in the window; \`entered\` is null for HubSpot and Attio, which keep no stage history, so null means unknown, not none. An Attio \`pipelineId\` is a list id, or \`deals\` for the stage on the deals themselves. Only GoHighLevel stages can be a step's rule (\`ghl_stage\`); HubSpot and Attio stages are evidence of how deals move, not something a rule can count.
|
|
708
708
|
- **webinars**: sign-ups, viewers and offer clicks per webinar id.
|