@letterstory/cli 0.176.99 → 0.176.101
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/lib/cli.mjs +4 -1
- package/lib/commands/admin.mjs +40 -3
- package/lib/commands/vary.mjs +16 -2
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
import { fetchParkedSections, withoutParked } from "./parked.mjs";
|
|
88
88
|
|
|
89
89
|
// Matches cli/package.json; publish-cli.yml rewrites both to the published version.
|
|
90
|
-
export const VERSION = "0.176.
|
|
90
|
+
export const VERSION = "0.176.101";
|
|
91
91
|
|
|
92
92
|
/** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
|
|
93
93
|
export const EXIT_PAYMENT_REQUIRED = 3;
|
|
@@ -96,6 +96,8 @@ export const EXIT_PAYMENT_REQUIRED = 3;
|
|
|
96
96
|
// can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
|
|
97
97
|
// `negate` spelling) in a command's ARGS map must be listed; boolean-flags.test.ts enforces it.
|
|
98
98
|
export const BOOLEAN_FLAGS = new Set([
|
|
99
|
+
// admin demo ideas: every live recipe, not only the Ideas that fit.
|
|
100
|
+
"library",
|
|
99
101
|
// admin targets check: check every target again, checked or not.
|
|
100
102
|
"recheck",
|
|
101
103
|
// build list: also move the builds' open changes along while polling.
|
|
@@ -1992,6 +1994,7 @@ Domains (the domains you hold, and free ones that match what people search):
|
|
|
1992
1994
|
Vary (A/B tests of a page's words and images on your own site):
|
|
1993
1995
|
vary [list] [--status running] [--site <id>] Your variationals and how many visitors each has seen
|
|
1994
1996
|
vary create --page <url> [--name <n>] [--goals-file <path>]
|
|
1997
|
+
vary launch [--brief <words>] [--page <url>] An A/B test Letter writes from the page and starts
|
|
1995
1998
|
vary get <id> Variants, their changes, and the results against the original
|
|
1996
1999
|
vary page <id> The page's copy as changes need it, and whether each variant still applies
|
|
1997
2000
|
vary save-variant <id> --deltas-file <path> [--key b] [--name <n>]
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
// admin letterpress companies | company <org-id> | facts <org-id> (the standing fit, per company)
|
|
23
23
|
// admin letterpress beyond [--limit N] [--before ISO] (what members asked that went past the library)
|
|
24
24
|
// admin letterpress settings|flip|set … (recipes:read / recipes:write)
|
|
25
|
-
// admin demo guide|list|show|set|reset|check …
|
|
25
|
+
// admin demo guide|list|show|set|reset|check|ideas … (demo:read / demo:write)
|
|
26
26
|
// admin deployments [--health down|failing|blocked|setting_up|live|paused|archived] [--org <id>] [--q <text>] [--archived] [--test] [--no-host] (fleet:read)
|
|
27
27
|
// admin models runs|run|star|unstar|scoreboard|requests|request|sampling … (models:read / models:write)
|
|
28
28
|
// admin replays [--org <id>] [--target <id>] [--status …] [--limit n] (fleet:read)
|
|
@@ -6808,7 +6808,8 @@ async function cmdAdminBilling(ctx) {
|
|
|
6808
6808
|
|
|
6809
6809
|
// `admin demo` — demo control (docs/architecture/demo-control.md): what each demo org shows,
|
|
6810
6810
|
// set, rehearsed and reset. The staff routes behind /superadmin/demo, the same functions and
|
|
6811
|
-
// schema as list_demo_orgs / get_demo_state / set_demo_state / reset_demo_state / run_demo_readiness_check
|
|
6811
|
+
// schema as list_demo_orgs / get_demo_state / set_demo_state / reset_demo_state / run_demo_readiness_check /
|
|
6812
|
+
// run_demo_ideas / get_demo_ideas_run.
|
|
6812
6813
|
const DEMO = "/api/superadmin/demo";
|
|
6813
6814
|
const DEMO_ITEM_FLAGS = [
|
|
6814
6815
|
"phantom",
|
|
@@ -6823,7 +6824,7 @@ const DEMO_ITEM_FLAGS = [
|
|
|
6823
6824
|
"setup",
|
|
6824
6825
|
];
|
|
6825
6826
|
const DEMO_USAGE =
|
|
6826
|
-
"Usage: admin demo guide | list [--enrollable] | show <org-id> [--moves] | set <org-id> [--enroll] [--unenroll] [--file <state.json>] [--phantom parked|shown] [--main-blog …] [--visitors …] [--probes not_run|shown] [--cms hidden|shown] [--publish-target …] [--search-console …] [--github …] [--domain …] [--setup fresh|finished] [--domain-cap n] [--inject <key>]... [--hide <key>]... [--save-as <name>] [--baseline <owner/repo>[@sha] | --clear-baseline] [--copy-from <org-id> [--copy-scenarios a,b] [--overwrite]] [--auto-reset <scenario>|off] [--every <minutes>] [--release] | domains | new <domain> [--name <n>] [--brief <t>] [--full] [--host vercel|pages] [--no-wait] | teardown <org-id> [--keep-repo] | bootstrap <org-id>... --from <org-id> [--scenarios a,b] [--overwrite] | reset <org-id> <scenario> [--clean-slate] [--close-prs since_applied|all_open|none] [--hold <minutes>] [--restore-repo revert|force] [--rebuild] [--reread-company] [--forget-company] [--forget-site] | check <org-id>";
|
|
6827
|
+
"Usage: admin demo guide | list [--enrollable] | show <org-id> [--moves] | set <org-id> [--enroll] [--unenroll] [--file <state.json>] [--phantom parked|shown] [--main-blog …] [--visitors …] [--probes not_run|shown] [--cms hidden|shown] [--publish-target …] [--search-console …] [--github …] [--domain …] [--setup fresh|finished] [--domain-cap n] [--inject <key>]... [--hide <key>]... [--save-as <name>] [--baseline <owner/repo>[@sha] | --clear-baseline] [--copy-from <org-id> [--copy-scenarios a,b] [--overwrite]] [--auto-reset <scenario>|off] [--every <minutes>] [--release] | domains | new <domain> [--name <n>] [--brief <t>] [--full] [--host vercel|pages] [--no-wait] | teardown <org-id> [--keep-repo] | bootstrap <org-id>... --from <org-id> [--scenarios a,b] [--overwrite] | reset <org-id> <scenario> [--clean-slate] [--close-prs since_applied|all_open|none] [--hold <minutes>] [--restore-repo revert|force] [--rebuild] [--reread-company] [--forget-company] [--forget-site] | check <org-id> | ideas <org-id> [--library] [--preview] [--force] | ideas <org-id> --status [--id <run-id>]";
|
|
6827
6828
|
|
|
6828
6829
|
const readinessLines = (r) =>
|
|
6829
6830
|
r
|
|
@@ -6833,6 +6834,22 @@ const readinessLines = (r) =>
|
|
|
6833
6834
|
].join("\n")
|
|
6834
6835
|
: "Not checked yet.";
|
|
6835
6836
|
|
|
6837
|
+
const ideasRunLines = (run) =>
|
|
6838
|
+
run
|
|
6839
|
+
? [
|
|
6840
|
+
`${run.summary} (${run.state}${run.note && run.state !== "done" ? `: ${run.note}` : ""})`,
|
|
6841
|
+
`${run.scope === "library" ? "every live recipe" : "Ideas"} on ${run.host}, ${run.delivery === "build" ? "previews" : "pull requests"}${run.force ? ", forced" : ""}, by ${run.started_by_name ?? "staff"} at ${run.created_at} run ${run.id}`,
|
|
6842
|
+
...run.items.map(
|
|
6843
|
+
(i) =>
|
|
6844
|
+
` ${i.outcome.padEnd(9)} ${i.title}${i.reason && i.outcome !== "started" ? ` [${i.reason}]` : ""}${
|
|
6845
|
+
i.build
|
|
6846
|
+
? ` build: ${i.build.archived ? "archived" : i.build.detail || i.build.kind}${i.build.pr_url ? ` ${i.build.pr_url}` : ""}`
|
|
6847
|
+
: ""
|
|
6848
|
+
}${i.message && i.outcome !== "started" ? `\n ${i.message}` : ""}`
|
|
6849
|
+
),
|
|
6850
|
+
].join("\n")
|
|
6851
|
+
: "No run yet.";
|
|
6852
|
+
|
|
6836
6853
|
async function cmdAdminDemo(ctx) {
|
|
6837
6854
|
const { flags, positionals, io } = ctx;
|
|
6838
6855
|
const sub = positionals[0];
|
|
@@ -7071,6 +7088,26 @@ async function cmdAdminDemo(ctx) {
|
|
|
7071
7088
|
printResult(io, flags, result, (r) => readinessLines(r.readiness));
|
|
7072
7089
|
return result.readiness?.ok ? 0 : 1;
|
|
7073
7090
|
}
|
|
7091
|
+
case "ideas": {
|
|
7092
|
+
// Every Idea on the demo org started for real (run_demo_ideas), or the latest run read (get_demo_ideas_run).
|
|
7093
|
+
const orgId = requirePositional(positionals, 1, "org-id");
|
|
7094
|
+
const path = `${DEMO}/${encodeURIComponent(orgId)}/ideas`;
|
|
7095
|
+
const id = flagStr(flags.id);
|
|
7096
|
+
const result =
|
|
7097
|
+
flagBool(flags.status) || id
|
|
7098
|
+
? await staffRequest(ctx, "GET", id ? `${path}?id=${encodeURIComponent(id)}` : path)
|
|
7099
|
+
: await staffPost(
|
|
7100
|
+
ctx,
|
|
7101
|
+
path,
|
|
7102
|
+
compact({
|
|
7103
|
+
scope: flagBool(flags.library) ? "library" : undefined,
|
|
7104
|
+
delivery: flagBool(flags.preview) ? "build" : undefined,
|
|
7105
|
+
force: flagBool(flags.force) || undefined,
|
|
7106
|
+
})
|
|
7107
|
+
);
|
|
7108
|
+
printResult(io, flags, result, (r) => ideasRunLines(r.run));
|
|
7109
|
+
return result.run?.state === "failed" ? 1 : 0;
|
|
7110
|
+
}
|
|
7074
7111
|
default:
|
|
7075
7112
|
throw new CliError(DEMO_USAGE);
|
|
7076
7113
|
}
|
package/lib/commands/vary.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
// `vary` — Variationals from a terminal: A/B tests of a page's words and images on your own site
|
|
2
2
|
// (docs/architecture/variationals.md). Thin wrappers over the variationals tools (list_variationals,
|
|
3
|
-
// get_variational, create_variational, update_variational, save_variational_variant,
|
|
3
|
+
// get_variational, create_variational, launch_variational_test, update_variational, save_variational_variant,
|
|
4
4
|
// remove_variational_variant, delete_variational, ship_variational_winner), the same lib functions the app calls.
|
|
5
5
|
//
|
|
6
6
|
// letterstory vary list [--status running]
|
|
7
7
|
// letterstory vary create --page https://acme.com/pricing [--name "Pricing headline"] [--goals-file goals.json]
|
|
8
|
+
// letterstory vary launch [--brief "Test the hero button"] [--page https://acme.com/] [--name <n>]
|
|
9
|
+
// made, given a challenger Letter writes from the page, and started (Ideas' A/B test row)
|
|
8
10
|
// letterstory vary get <id>
|
|
9
11
|
// letterstory vary page <id> the page's blocks, as a change's tag/before/occurrence
|
|
10
12
|
// letterstory vary save-variant <id> --deltas-file b.json [--key b] [--name "Shorter headline"]
|
|
@@ -74,6 +76,12 @@ export const ARGS = {
|
|
|
74
76
|
name: "name",
|
|
75
77
|
goals: jsonFile("goals-file", "goals"),
|
|
76
78
|
},
|
|
79
|
+
launch_variational_test: {
|
|
80
|
+
brief: "brief",
|
|
81
|
+
page_url: "page",
|
|
82
|
+
site_id: "site",
|
|
83
|
+
name: "name",
|
|
84
|
+
},
|
|
77
85
|
ship_variational_winner: {
|
|
78
86
|
variational_id: variationalId,
|
|
79
87
|
variant: "variant",
|
|
@@ -135,6 +143,12 @@ export async function cmdVary(ctx) {
|
|
|
135
143
|
case "create":
|
|
136
144
|
refuseUnknownFlags(rest, ARGS.create_variational, ["goals-file"]);
|
|
137
145
|
return varyShow(rest, await call(rest, "create_variational"));
|
|
146
|
+
case "launch": {
|
|
147
|
+
refuseUnknownFlags(rest, ARGS.launch_variational_test, []);
|
|
148
|
+
const result = await call(rest, "launch_variational_test");
|
|
149
|
+
printResult(rest.io, rest.flags, result, (r) => `${r.message}\n${r.variational.edit_url}`);
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
138
152
|
case "update":
|
|
139
153
|
case "weights":
|
|
140
154
|
case "goals":
|
|
@@ -170,7 +184,7 @@ export async function cmdVary(ctx) {
|
|
|
170
184
|
}
|
|
171
185
|
default:
|
|
172
186
|
throw new CliError(
|
|
173
|
-
"Usage: vary [list|get|page|create|update|weights|goals|start|pause|end|save-variant|remove-variant|ship|delete]"
|
|
187
|
+
"Usage: vary [list|get|page|create|launch|update|weights|goals|start|pause|end|save-variant|remove-variant|ship|delete]"
|
|
174
188
|
);
|
|
175
189
|
}
|
|
176
190
|
}
|