@letterstory/cli 0.177.21 → 0.177.23
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 +6 -3
- package/lib/commands/admin.mjs +43 -6
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -88,7 +88,7 @@ import {
|
|
|
88
88
|
import { fetchParkedSections, withoutParked } from "./parked.mjs";
|
|
89
89
|
|
|
90
90
|
// Matches cli/package.json; publish-cli.yml rewrites both to the published version.
|
|
91
|
-
export const VERSION = "0.177.
|
|
91
|
+
export const VERSION = "0.177.23";
|
|
92
92
|
|
|
93
93
|
/** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
|
|
94
94
|
export const EXIT_PAYMENT_REQUIRED = 3;
|
|
@@ -106,6 +106,8 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
106
106
|
"pull-requests",
|
|
107
107
|
"make-orgs",
|
|
108
108
|
"no-refit",
|
|
109
|
+
// admin demo sweep --new-org: one fresh test org for exactly the picks.
|
|
110
|
+
"new-org",
|
|
109
111
|
// build --check: read every gate a start meets and start nothing.
|
|
110
112
|
"check",
|
|
111
113
|
// admin invariants: press every startable row as a check too.
|
|
@@ -1226,11 +1228,12 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
1226
1228
|
admin demo ideas <org-id> [--library] [--preview] [--force] | --status [--id <run>]
|
|
1227
1229
|
Start every Idea on a demo org for real (pull requests, or
|
|
1228
1230
|
previews), or read how the latest run went.
|
|
1229
|
-
admin demo sweep [--prepare] [--pull-requests] [--recipes a,b] [--orgs a,b] [--exclude a,b] [--buy a,b] [--make-orgs] [--no-refit] | --status [--id <sweep>]
|
|
1231
|
+
admin demo sweep [--prepare] [--pull-requests] [--recipes a,b] [--variation <n|name>] [--pick <recipe>[:<variation>]]... [--new-org] [--orgs a,b] [--exclude a,b] [--buy a,b] [--make-orgs] [--no-refit] | --status [--id <sweep>] | --reset <recipe> [--id <sweep>]
|
|
1230
1232
|
Every live recipe end to end: each gets a test org whose Ideas
|
|
1231
1233
|
offers it, its Start pressed (or, with --prepare, left for you
|
|
1232
1234
|
to press in the app), and its outcome judged, with who owns a
|
|
1233
|
-
failure.
|
|
1235
|
+
failure. --new-org --pick a --pick b:2 makes one fresh test org
|
|
1236
|
+
for exactly those recipes. Exits 1 when the sweep failed.
|
|
1234
1237
|
admin brand-detection <org-id> [--term <t>]... [--exact <t>]... [--exclude <phrase>]... [--note "…"] | --clear [--note "…"]
|
|
1235
1238
|
How a client's brand is detected in AI answers, with
|
|
1236
1239
|
every earlier setting; with flags, set the exact set
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -7007,7 +7007,7 @@ const DEMO_ITEM_FLAGS = [
|
|
|
7007
7007
|
"setup",
|
|
7008
7008
|
];
|
|
7009
7009
|
const DEMO_USAGE =
|
|
7010
|
-
"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>] | sweep [--prepare] [--pull-requests] [--recipes <id>,…] [--orgs <id>,…] [--exclude <id>,…] [--buy <recipe-id>,…] [--make-orgs] [--no-refit] | sweep --status [--id <sweep-id>]";
|
|
7010
|
+
"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>] | sweep [--prepare] [--pull-requests] [--recipes <id>,…] [--variation <n|name>] [--pick <recipe>[:<variation>]]... [--new-org] [--orgs <id>,…] [--exclude <id>,…] [--buy <recipe-id>,…] [--make-orgs] [--no-refit] | sweep --status [--id <sweep-id>] | sweep --reset <recipe-id> [--id <sweep-id>]";
|
|
7011
7011
|
|
|
7012
7012
|
const readinessLines = (r) =>
|
|
7013
7013
|
r
|
|
@@ -7044,15 +7044,35 @@ const SWEEP_MARK = {
|
|
|
7044
7044
|
pending: "…",
|
|
7045
7045
|
};
|
|
7046
7046
|
|
|
7047
|
+
/** A variation flag: a number is its place (1 is the recipe itself); anything else its name. */
|
|
7048
|
+
const variationFlag = (v) => (v ? (/^\d+$/.test(v) ? Number(v) : v) : undefined);
|
|
7049
|
+
|
|
7050
|
+
/** `--pick <recipe>[:<variation>]`: a recipe in its variation (the first colon splits; a name may hold more). */
|
|
7051
|
+
const pickFlag = (v) => {
|
|
7052
|
+
const at = v.indexOf(":");
|
|
7053
|
+
return at < 0
|
|
7054
|
+
? { recipe: v.trim() }
|
|
7055
|
+
: compact({ recipe: v.slice(0, at).trim(), variation: variationFlag(v.slice(at + 1).trim()) });
|
|
7056
|
+
};
|
|
7057
|
+
|
|
7058
|
+
/** A new test org's stages (get_recipe_sweep `new_org`). */
|
|
7059
|
+
const NEW_ORG_STAGE = { site: "site written", connected: "connected", setup: "setup done", fit: "fit decided" };
|
|
7060
|
+
|
|
7047
7061
|
/** A recipe sweep's report (get_recipe_sweep), one block per recipe. */
|
|
7048
7062
|
const recipeSweepLines = (sweep, appUrl) =>
|
|
7049
7063
|
sweep
|
|
7050
7064
|
? [
|
|
7051
7065
|
`${sweep.summary} (${sweep.state}${sweep.note && sweep.state !== "done" ? `: ${sweep.note}` : ""})`,
|
|
7052
7066
|
`${sweep.start ? "started by the sweep" : "prepared for you to start"}, ${sweep.delivery === "build" ? "previews" : "pull requests"}, by ${sweep.started_by_name ?? "staff"} at ${sweep.created_at} sweep ${sweep.id}`,
|
|
7067
|
+
...(sweep.new_org
|
|
7068
|
+
? [
|
|
7069
|
+
`new test org: ${sweep.new_org.name ?? sweep.new_org.domain ?? "being made"} ${sweep.new_org.status === "done" ? "ready" : `${sweep.new_org.status}: ${NEW_ORG_STAGE[sweep.new_org.current] ?? sweep.new_org.current}`}${sweep.new_org.note ? ` (${sweep.new_org.note})` : ""}`,
|
|
7070
|
+
sweep.new_org.ideas ? ` open org: ${appUrl}${sweep.new_org.ideas}` : null,
|
|
7071
|
+
].filter(Boolean)
|
|
7072
|
+
: []),
|
|
7053
7073
|
...sweep.items.map((i) =>
|
|
7054
7074
|
[
|
|
7055
|
-
`\n${(SWEEP_MARK[i.result] ?? i.result).padEnd(10)} ${i.name}`,
|
|
7075
|
+
`\n${(SWEEP_MARK[i.result] ?? i.result).padEnd(10)} ${i.name}${i.variation ? ` (variation ${i.variation}: ${i.variation_name ?? ""})` : ""}`,
|
|
7056
7076
|
i.org ? ` org: ${i.org.name} (${i.org.host})${i.org.made ? ", made for it" : ""}` : null,
|
|
7057
7077
|
i.fit[0] ? ` fit: ${i.fit[0].fits}: ${i.fit[0].why}` : null,
|
|
7058
7078
|
i.row
|
|
@@ -7063,6 +7083,7 @@ const recipeSweepLines = (sweep, appUrl) =>
|
|
|
7063
7083
|
: null,
|
|
7064
7084
|
i.verdict ? ` outcome: ${i.verdict.state}: ${i.verdict.observed}` : null,
|
|
7065
7085
|
i.cause ? ` cause: ${i.cause.owner}: ${i.cause.why}` : null,
|
|
7086
|
+
...(i.tried ?? []).map((t) => ` tried ${t.name}: ${t.why}`),
|
|
7066
7087
|
i.profile_problem ? ` profile: ${i.profile_problem}` : null,
|
|
7067
7088
|
i.profile?.unsettable?.length
|
|
7068
7089
|
? ` can't be made on a test org: ${i.profile.unsettable.map((u) => u.key).join(", ")}`
|
|
@@ -7338,6 +7359,18 @@ async function cmdAdminDemo(ctx) {
|
|
|
7338
7359
|
// Every live recipe end to end on test orgs (run_recipe_sweep), or the latest sweep's report (get_recipe_sweep).
|
|
7339
7360
|
const path = `${DEMO}/sweeps`;
|
|
7340
7361
|
const id = flagStr(flags.id);
|
|
7362
|
+
// The retest loop: one recipe brought back on its test org (reset_recipe_sweep_item).
|
|
7363
|
+
if (flagStr(flags.reset)) {
|
|
7364
|
+
const reset = await staffPost(ctx, `${path}/reset`, compact({ id, recipe_id: flagStr(flags.reset) }));
|
|
7365
|
+
printResult(io, flags, reset, (r) =>
|
|
7366
|
+
[
|
|
7367
|
+
...r.reset.undone.map((u) => `undone: ${u}`),
|
|
7368
|
+
...r.reset.kept.map((k) => `kept: ${k}`),
|
|
7369
|
+
recipeSweepLines(r.sweep, ctx.client.url),
|
|
7370
|
+
].join("\n")
|
|
7371
|
+
);
|
|
7372
|
+
return 0;
|
|
7373
|
+
}
|
|
7341
7374
|
const result =
|
|
7342
7375
|
flagBool(flags.status) || id
|
|
7343
7376
|
? await staffRequest(ctx, "GET", id ? `${path}?id=${encodeURIComponent(id)}` : path)
|
|
@@ -7347,10 +7380,14 @@ async function cmdAdminDemo(ctx) {
|
|
|
7347
7380
|
compact({
|
|
7348
7381
|
start: flagBool(flags.prepare) ? false : undefined,
|
|
7349
7382
|
delivery: flagBool(flags["pull-requests"]) ? "build_pr" : undefined,
|
|
7350
|
-
recipes: flags.recipes ?
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7383
|
+
recipes: flags.recipes ? flagCsv(flags.recipes) : undefined,
|
|
7384
|
+
variation: variationFlag(flagStr(flags.variation)),
|
|
7385
|
+
// --pick <recipe>[:<variation>], repeatable: each recipe in its variation.
|
|
7386
|
+
picks: flags.pick ? flagList(flags.pick).map(pickFlag) : undefined,
|
|
7387
|
+
new_org: flagBool(flags["new-org"]) || undefined,
|
|
7388
|
+
orgs: flags.orgs ? flagCsv(flags.orgs) : undefined,
|
|
7389
|
+
exclude: flags.exclude ? flagCsv(flags.exclude) : undefined,
|
|
7390
|
+
purchases: flags.buy ? flagCsv(flags.buy) : undefined,
|
|
7354
7391
|
make_orgs: flagBool(flags["make-orgs"]) || undefined,
|
|
7355
7392
|
refit: flagBool(flags["no-refit"]) ? false : undefined,
|
|
7356
7393
|
})
|