@letterstory/cli 0.176.50 → 0.176.52
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 -2
- package/lib/commands/admin.mjs +50 -1
- package/lib/commands/build.mjs +3 -2
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -85,7 +85,7 @@ import {
|
|
|
85
85
|
import { fetchParkedSections, withoutParked } from "./parked.mjs";
|
|
86
86
|
|
|
87
87
|
// Matches cli/package.json; publish-cli.yml rewrites both to the published version.
|
|
88
|
-
export const VERSION = "0.176.
|
|
88
|
+
export const VERSION = "0.176.52";
|
|
89
89
|
|
|
90
90
|
/** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
|
|
91
91
|
export const EXIT_PAYMENT_REQUIRED = 3;
|
|
@@ -177,6 +177,8 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
177
177
|
"no-modifiers",
|
|
178
178
|
// site map: do not start an audit for a host that has none.
|
|
179
179
|
"no-audit",
|
|
180
|
+
// admin deployments: answer from our rows alone, without reading the host.
|
|
181
|
+
"no-host",
|
|
180
182
|
// site metrics: skip the previous window (no deltas, no revamp indicator).
|
|
181
183
|
"no-compare",
|
|
182
184
|
// site refresh / observe: the loop's switches.
|
|
@@ -1005,6 +1007,10 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
1005
1007
|
read-only SQL across every org; --sql prints
|
|
1006
1008
|
the queries behind the answer. Needs the
|
|
1007
1009
|
fleet:query capability on the staff key.
|
|
1010
|
+
admin deployments [--health down|failing|…] [--org <id>] [--q <text>] [--archived] [--test] [--no-host] [--json]
|
|
1011
|
+
Every site Letter built and hosts, across every org,
|
|
1012
|
+
worst first: health, the problem, and what the host
|
|
1013
|
+
has that no app names. Needs fleet:read.
|
|
1008
1014
|
admin recipes list | show <id|name> | vocab | stats Recipes: Letter's one library of direction for
|
|
1009
1015
|
Letterpress on Plan, Build and Fix (/superadmin/recipes),
|
|
1010
1016
|
each a name, a description, the recipe (what Letterpress
|
|
@@ -1741,7 +1747,8 @@ Build (a change to your site, or launching what isn't code; the Build box's own
|
|
|
1741
1747
|
build status <build-id> One build: each change's state, its preview and pull request
|
|
1742
1748
|
build follow <build-id> [--json] What its agents do, line by line, until nothing in it is at
|
|
1743
1749
|
work (as letterpress follows a build); --json: one line per event
|
|
1744
|
-
build conversations [--limit <n>]
|
|
1750
|
+
build conversations [--limit <n>] [--origin <door>] Your conversations with Build, most recently active first;
|
|
1751
|
+
--origin console: only the Build box's (letter_edit: ⌘L's)
|
|
1745
1752
|
build conversation <conversation-id> | --build <build-id>
|
|
1746
1753
|
Every message in one, oldest first
|
|
1747
1754
|
|
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 settings|flip|set … (recipes:read / recipes:write)
|
|
25
25
|
// admin demo guide|list|show|set|reset|check … (demo:read / demo:write)
|
|
26
|
+
// admin deployments [--health down|failing|blocked|setting_up|live|paused|archived] [--org <id>] [--q <text>] [--archived] [--test] [--no-host] (fleet:read)
|
|
26
27
|
// admin models runs|run|star|unstar|scoreboard|requests|request|sampling … (models:read / models:write)
|
|
27
28
|
// admin replays [--org <id>] [--target <id>] [--status …] [--limit n] (fleet:read)
|
|
28
29
|
// admin replay --org <id> [<response-id> | --target <id>] [--surface …] (fleet:replay)
|
|
@@ -6960,11 +6961,59 @@ export async function cmdAdmin(ctx) {
|
|
|
6960
6961
|
if (sub === "recipes") return cmdAdminRecipes({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
6961
6962
|
if (sub === "letterpress") return cmdAdminLetterpress({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
6962
6963
|
if (sub === "demo") return cmdAdminDemo({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
6964
|
+
if (sub === "deployments" || sub === "deploys")
|
|
6965
|
+
return cmdAdminDeployments({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
6963
6966
|
throw new CliError(
|
|
6964
|
-
'Usage: admin recipes … | admin letterpress … | admin demo … | 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)'
|
|
6967
|
+
'Usage: admin recipes … | admin letterpress … | admin demo … | 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)'
|
|
6965
6968
|
);
|
|
6966
6969
|
}
|
|
6967
6970
|
|
|
6971
|
+
const MANAGED_HEALTH = ["down", "failing", "blocked", "setting_up", "live", "paused", "archived"];
|
|
6972
|
+
|
|
6973
|
+
// `admin deployments` — every site Letter built and hosts, across every organization
|
|
6974
|
+
// (docs/architecture/deployments.md, "Every managed site"): worst first, each with its org, domain,
|
|
6975
|
+
// health and the problem in one sentence, then what the host has that no app of ours names. The
|
|
6976
|
+
// same read as Super Admin → Deployments and the staff-only `list_managed_deployments` tool.
|
|
6977
|
+
async function cmdAdminDeployments(ctx) {
|
|
6978
|
+
const { flags, io } = ctx;
|
|
6979
|
+
const health = flagStr(flags.health);
|
|
6980
|
+
if (health !== undefined && !MANAGED_HEALTH.includes(health))
|
|
6981
|
+
throw new CliError(`--health is one of ${MANAGED_HEALTH.join(", ")}.`);
|
|
6982
|
+
const params = new URLSearchParams();
|
|
6983
|
+
if (health) params.set("health", health);
|
|
6984
|
+
if (flagStr(flags.org)) params.set("org_id", flagStr(flags.org));
|
|
6985
|
+
if (flagStr(flags.q)) params.set("q", flagStr(flags.q));
|
|
6986
|
+
if (flagBool(flags.archived)) params.set("include_archived", "1");
|
|
6987
|
+
if (flagBool(flags.test)) params.set("include_test", "1");
|
|
6988
|
+
if (flagBool(flags["no-host"])) params.set("check_host", "0");
|
|
6989
|
+
const qs = params.toString();
|
|
6990
|
+
const result = await staffRequest(ctx, "GET", `/api/superadmin/deployments${qs ? `?${qs}` : ""}`);
|
|
6991
|
+
printResult(io, flags, result, (r) => {
|
|
6992
|
+
const c = r.counts;
|
|
6993
|
+
const lines = [
|
|
6994
|
+
`${c.total} managed site${c.total === 1 ? "" : "s"} across ${c.orgs} org${c.orgs === 1 ? "" : "s"}: ` +
|
|
6995
|
+
MANAGED_HEALTH.filter((h) => c[h] > 0)
|
|
6996
|
+
.map((h) => `${c[h]} ${h.replace("_", " ")}`)
|
|
6997
|
+
.join(", "),
|
|
6998
|
+
];
|
|
6999
|
+
if (!r.apps.length) lines.push(" (none match)");
|
|
7000
|
+
for (const a of r.apps) {
|
|
7001
|
+
lines.push(
|
|
7002
|
+
`${a.id} ${a.health.padEnd(10)} ${a.name.slice(0, 26).padEnd(26)} ${(a.org.name ?? a.org.id).slice(0, 22).padEnd(22)} ${a.url ?? a.domain ?? "no domain yet"}`
|
|
7003
|
+
);
|
|
7004
|
+
if (a.problem) lines.push(` ${a.problem}`);
|
|
7005
|
+
else if (a.health === "setting_up" && a.stage_note) lines.push(` ${a.stage}: ${a.stage_note}`);
|
|
7006
|
+
}
|
|
7007
|
+
if (r.host.read) {
|
|
7008
|
+
lines.push("", `Host: ${r.host.apps} app${r.host.apps === 1 ? "" : "s"} on our account.`);
|
|
7009
|
+
for (const u of r.host.untracked)
|
|
7010
|
+
lines.push(` untracked ${u.name} (${u.status}) ${u.url ?? ""}`.trimEnd());
|
|
7011
|
+
} else lines.push("", `Host not read: ${r.host.note}`);
|
|
7012
|
+
return lines.join("\n");
|
|
7013
|
+
});
|
|
7014
|
+
return 0;
|
|
7015
|
+
}
|
|
7016
|
+
|
|
6968
7017
|
// `admin brand-detection <org-id>` — how the client's brand is detected in AI answers;
|
|
6969
7018
|
// with --term / --exact / --exclude it SETS the exact set (replacing the inferred one),
|
|
6970
7019
|
// --clear goes back to inferred (recorded as a decision, with --note as the why). Every
|
package/lib/commands/build.mjs
CHANGED
|
@@ -138,7 +138,8 @@ const ARGS = {
|
|
|
138
138
|
// --from-plan: only what the Plan started (a strategy's row, Auto-Plan's pick), as the Plan's Actions list shows it.
|
|
139
139
|
from_plan: { flag: "from-plan", type: "bool" },
|
|
140
140
|
},
|
|
141
|
-
|
|
141
|
+
// --origin console: only what the app's Build box started (letter_edit: ⌘L's, mcp: the terminal's or an agent's).
|
|
142
|
+
list_build_conversations: { limit: { flag: "limit", type: "num" }, origin: "origin" },
|
|
142
143
|
get_build_conversation: {
|
|
143
144
|
conversation_id: { positional: 0, label: "conversation-id" },
|
|
144
145
|
build_id: "build",
|
|
@@ -403,7 +404,7 @@ async function buildFollow(ctx) {
|
|
|
403
404
|
/** `build conversations`: the organization's conversations with Build, most recently active first. */
|
|
404
405
|
async function buildConversations(ctx) {
|
|
405
406
|
const { client, flags, io } = ctx;
|
|
406
|
-
refuseUnknownFlags(ctx, {}, ["limit"]);
|
|
407
|
+
refuseUnknownFlags(ctx, {}, ["limit", "origin"]);
|
|
407
408
|
const result = await client.callTool(
|
|
408
409
|
"list_build_conversations",
|
|
409
410
|
argsFromFlags(ARGS.list_build_conversations, flags)
|