@letterstory/cli 0.177.17 → 0.177.18
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 +9 -1
- package/lib/commands/admin.mjs +38 -1
- package/lib/commands/build.mjs +4 -0
- 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.18";
|
|
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,10 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
106
106
|
"pull-requests",
|
|
107
107
|
"make-orgs",
|
|
108
108
|
"no-refit",
|
|
109
|
+
// build --check: read every gate a start meets and start nothing.
|
|
110
|
+
"check",
|
|
111
|
+
// admin invariants: press every startable row as a check too.
|
|
112
|
+
"presses",
|
|
109
113
|
// admin targets check: check every target again, checked or not.
|
|
110
114
|
"recheck",
|
|
111
115
|
// build list: also move the builds' open changes along while polling.
|
|
@@ -1126,6 +1130,10 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
1126
1130
|
admin recipes reread --org <id>,… Read these companies from their sites again: what was
|
|
1127
1131
|
only ever inferred is replaced, what the company changed
|
|
1128
1132
|
is kept. Refit them after. Needs recipes:write.
|
|
1133
|
+
admin invariants [--org <id>,…] [--limit 50] [--presses]
|
|
1134
|
+
The Ideas invariants over production, read only: rows a
|
|
1135
|
+
start would refuse, builds whose reading disagrees with
|
|
1136
|
+
what they hold, grouped with ids. Exits 1 on any.
|
|
1129
1137
|
admin targets check [--org <id>,…] [--recheck] [--limit 10]
|
|
1130
1138
|
Check ranking targets' phrases (buyer intent, self-named,
|
|
1131
1139
|
search demand, fit) and store each verdict: --org those
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
// admin letterpress beyond [--limit N] [--before ISO] (what members asked that went past the library)
|
|
24
24
|
// admin letterpress endings [--days N] [--write-cases] (how turns and repo changes ended when not done, by owner)
|
|
25
25
|
// admin letterpress settings|flip|set … (recipes:read / recipes:write)
|
|
26
|
+
// admin invariants [--org <id>,…] [--limit N] [--presses] (staff)
|
|
26
27
|
// admin demo guide|list|show|set|reset|check|ideas … (demo:read / demo:write)
|
|
27
28
|
// admin deployments [--health down|failing|blocked|setting_up|live|paused|archived] [--org <id>] [--q <text>] [--archived] [--test] [--no-host] (fleet:read)
|
|
28
29
|
// admin models runs|run|star|unstar|scoreboard|requests|request|sampling … (models:read / models:write)
|
|
@@ -62,7 +63,42 @@ import {
|
|
|
62
63
|
compact,
|
|
63
64
|
ok,
|
|
64
65
|
requirePositional,
|
|
66
|
+
argsFromFlags,
|
|
65
67
|
} from "./shared.mjs";
|
|
68
|
+
|
|
69
|
+
// `admin invariants`: the one tool it calls, its flags declared (scripts/parity-check.ts reads this map).
|
|
70
|
+
export const ARGS = {
|
|
71
|
+
check_ideas_invariants: {
|
|
72
|
+
org_ids: { value: (flags) => (flags.org ? flagCsv(flags.org) : undefined) },
|
|
73
|
+
limit: { flag: "limit", type: "num" },
|
|
74
|
+
presses: { flag: "presses", type: "bool" },
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const INVARIANT_LIMIT = 30;
|
|
79
|
+
|
|
80
|
+
// `admin invariants` — the Ideas invariants over production (docs/architecture/ideas-invariants.md), read only:
|
|
81
|
+
// check_ideas_invariants, grouped by invariant with ids. Exits 1 when any holds false.
|
|
82
|
+
async function cmdAdminInvariants(ctx) {
|
|
83
|
+
const { client, flags, io } = ctx;
|
|
84
|
+
const result = await client.callTool("check_ideas_invariants", argsFromFlags(ARGS.check_ideas_invariants, flags));
|
|
85
|
+
printResult(io, flags, result, (r) =>
|
|
86
|
+
[
|
|
87
|
+
`${r.total} violation(s) on ${r.accounts} account(s)${r.unread.length ? `, ${r.unread.length} not read` : ""}.`,
|
|
88
|
+
...r.by_invariant.map((g) =>
|
|
89
|
+
[
|
|
90
|
+
`\n${g.invariant} ${g.count} (${g.owner})`,
|
|
91
|
+
...g.violations
|
|
92
|
+
.slice(0, INVARIANT_LIMIT)
|
|
93
|
+
.map((v) => ` ${v.host} ${v.org_id} ${v.subject}\n ${v.evidence}`),
|
|
94
|
+
...(g.count > INVARIANT_LIMIT ? [` … ${g.count - INVARIANT_LIMIT} more (--json for all)`] : []),
|
|
95
|
+
].join("\n")
|
|
96
|
+
),
|
|
97
|
+
...r.unread.map((u) => `not read: ${u.org_id}: ${u.error}`),
|
|
98
|
+
].join("\n")
|
|
99
|
+
);
|
|
100
|
+
return result.total > 0 ? 1 : 0;
|
|
101
|
+
}
|
|
66
102
|
import { watchDomainJob } from "./onboard.mjs";
|
|
67
103
|
|
|
68
104
|
const SEER_MODES = ["suggest", "skip"];
|
|
@@ -7349,10 +7385,11 @@ export async function cmdAdmin(ctx) {
|
|
|
7349
7385
|
if (sub === "letterpress") return cmdAdminLetterpress({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
7350
7386
|
if (sub === "demo") return cmdAdminDemo({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
7351
7387
|
if (sub === "targets") return cmdAdminTargets({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
7388
|
+
if (sub === "invariants") return cmdAdminInvariants({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
7352
7389
|
if (sub === "deployments" || sub === "deploys")
|
|
7353
7390
|
return cmdAdminDeployments({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
7354
7391
|
throw new CliError(
|
|
7355
|
-
'Usage: admin recipes … | admin letterpress … | admin demo … | admin targets … | admin deployments … | admin republish … | admin create-org --domain <bare-domain> [--onboard] … | admin ask "<question>" | admin patterns … | admin experiments … | admin fleet-experiments … | admin crm … | admin spend … | admin evals … | admin brand-detection … | admin tuning … | admin tuning-context | admin replays … (see --help)'
|
|
7392
|
+
'Usage: admin recipes … | admin letterpress … | admin demo … | admin targets … | admin invariants … | admin deployments … | admin republish … | admin create-org --domain <bare-domain> [--onboard] … | admin ask "<question>" | admin patterns … | admin experiments … | admin fleet-experiments … | admin crm … | admin spend … | admin evals … | admin brand-detection … | admin tuning … | admin tuning-context | admin replays … (see --help)'
|
|
7356
7393
|
);
|
|
7357
7394
|
}
|
|
7358
7395
|
|
package/lib/commands/build.mjs
CHANGED
|
@@ -105,6 +105,8 @@ const ARGS = {
|
|
|
105
105
|
site_name: "site-name",
|
|
106
106
|
// --plan-only: answer what it would do and start nothing (--json for the plan to send back).
|
|
107
107
|
plan_only: { flag: "plan-only", type: "bool" },
|
|
108
|
+
// --check: read every gate and say whether a press would start it, starting and recording nothing.
|
|
109
|
+
check: { flag: "check", type: "bool" },
|
|
108
110
|
// --plan-only always plans what it's given, as /plan does: it was asked for by name.
|
|
109
111
|
asked_to_plan: { value: (flags) => (flags["plan-only"] ? true : undefined) },
|
|
110
112
|
// --plan-file <path>: build exactly the plan --plan-only answered.
|
|
@@ -281,6 +283,7 @@ async function buildStart(ctx) {
|
|
|
281
283
|
"plan-only",
|
|
282
284
|
"plan-file",
|
|
283
285
|
"branch",
|
|
286
|
+
"check",
|
|
284
287
|
...FILE_FLAGS,
|
|
285
288
|
]);
|
|
286
289
|
const files = await attachedFiles(ctx);
|
|
@@ -294,6 +297,7 @@ async function buildStart(ctx) {
|
|
|
294
297
|
...r.plan.changes.map((c) => ` ${c.title ?? c.instructions}`),
|
|
295
298
|
...r.plan.actions.map((a) => ` ${a.title}`),
|
|
296
299
|
].join("\n");
|
|
300
|
+
if (r.status === "would_start") return r.message ?? "This would start now.";
|
|
297
301
|
if (r.status !== "started") return r.message ?? r.status;
|
|
298
302
|
const steps = (r.build?.steps ?? []).map((s) => ` ${s.status} ${s.title}${s.note ? `: ${s.note}` : ""}`);
|
|
299
303
|
return [`Started: ${r.build.title} (${r.build.id})`, ...steps].join("\n");
|