@letterstory/cli 0.122.0 → 0.124.0
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 +7 -2
- package/lib/commands/admin.mjs +108 -2
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -61,13 +61,15 @@ import {
|
|
|
61
61
|
} from "./commands.mjs";
|
|
62
62
|
|
|
63
63
|
// Keep in sync with cli/package.json.
|
|
64
|
-
export const VERSION = "0.
|
|
64
|
+
export const VERSION = "0.124.0";
|
|
65
65
|
|
|
66
66
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
67
67
|
// can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
|
|
68
68
|
// `negate` spelling) in a command's ARGS map must be listed; boolean-flags.test.ts enforces it.
|
|
69
69
|
export const BOOLEAN_FLAGS = new Set([
|
|
70
70
|
"json",
|
|
71
|
+
// admin models runs: only the starred ones.
|
|
72
|
+
"starred",
|
|
71
73
|
// shredder file / arena file: save the version as a candidate beside live.
|
|
72
74
|
"candidate",
|
|
73
75
|
// site tree: include children a fold-by-default family would hide; items over the whole subtree.
|
|
@@ -843,6 +845,8 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
843
845
|
session (a trial per arm), linked to its
|
|
844
846
|
ledger entry. Written by \`npm run lab --
|
|
845
847
|
publish\` in the kernels repo.
|
|
848
|
+
admin models runs [--model M] [--starred] | run <id> | star|unstar <id> | scoreboard --model M
|
|
849
|
+
The model hub's saved runs and blind arena (models.letter.dev)
|
|
846
850
|
admin spend summary [--range day|week|month|year | --from D --to D] [--grain day|week|month]
|
|
847
851
|
| reconcile [--from D --to D] | pnl [--range day|week|month|year | --from D --to D]
|
|
848
852
|
| reference add --vendor V [--key K] --metric billed_usd --value N --from D [--to D] --ref "…"
|
|
@@ -851,7 +855,8 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
851
855
|
| add --vendor V --amount N --from D [--to D] --area A --category C [--basis billed|estimated] …
|
|
852
856
|
| import <file.csv> [--vendor Concentrate] [--area A] [--ledger-key K] [--dry-run]
|
|
853
857
|
| import <file.csv> [--vendor Concentrate] [--area A] [--keep-ledger-key] [--dry-run]
|
|
854
|
-
| usage <events.json> per-call costs as kernels/lettertrace push them
|
|
858
|
+
| usage <events.json> per-call costs as kernels/lettertrace/models push them
|
|
859
|
+
| usage list --source models --from D --to D one source's calls back, newest first
|
|
855
860
|
| remove <entry-id> | services | service <slug> [--owner …] [--monthly N|none] [--renewal D] [--units N|none]
|
|
856
861
|
Where Letter's money goes (spending.letter.dev):
|
|
857
862
|
totals, run rate, area/vendor/provider/model/
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
// admin brand-detection <org-id> (fleet:read)
|
|
20
20
|
// admin brand-detection <org-id> [--term t]... [--exact t]... [--exclude p]... [--note "…"] | --clear [--note "…"] (fleet:instrument)
|
|
21
21
|
// admin recipes list|show|vocab|export|import|save|delete … (recipes:read / recipes:write)
|
|
22
|
+
// admin models runs|run|star|unstar|scoreboard … (models:read / models:write)
|
|
22
23
|
// admin replays [--org <id>] [--target <id>] [--status …] [--limit n] (fleet:read)
|
|
23
24
|
// admin replay --org <id> [<response-id> | --target <id>] [--surface …] (fleet:replay)
|
|
24
25
|
// admin create-org --domain acme.com [--name "Acme"] [--test] [--no-key] [--key-name N]
|
|
@@ -3962,6 +3963,83 @@ function spendEntryFromFlags(flags) {
|
|
|
3962
3963
|
});
|
|
3963
3964
|
}
|
|
3964
3965
|
|
|
3966
|
+
const MODELS = "/api/superadmin/models";
|
|
3967
|
+
const MODELS_USAGE =
|
|
3968
|
+
"Usage: admin models runs [--model ballpoint-1] [--starred] [--limit N] | run <id> | star <id> | unstar <id> | scoreboard --model ballpoint-1";
|
|
3969
|
+
|
|
3970
|
+
/** The model hub's saved runs and blind arena (models.letter.dev), same functions as its pages. */
|
|
3971
|
+
async function cmdAdminModels(ctx) {
|
|
3972
|
+
const { flags, positionals, io } = ctx;
|
|
3973
|
+
const sub = positionals[0];
|
|
3974
|
+
switch (sub) {
|
|
3975
|
+
case "runs": {
|
|
3976
|
+
const params = new URLSearchParams(
|
|
3977
|
+
compact({
|
|
3978
|
+
model: flagStr(flags.model),
|
|
3979
|
+
starred: flagBool(flags.starred) ? "true" : undefined,
|
|
3980
|
+
limit: flagNum(flags.limit)?.toString(),
|
|
3981
|
+
})
|
|
3982
|
+
);
|
|
3983
|
+
const result = await staffRequest(ctx, "GET", `${MODELS}/runs${params.size ? `?${params}` : ""}`);
|
|
3984
|
+
printResult(io, flags, result, (r) =>
|
|
3985
|
+
(r.runs ?? [])
|
|
3986
|
+
.map(
|
|
3987
|
+
(x) =>
|
|
3988
|
+
`${x.created_at.slice(0, 16)} ${x.starred ? "★" : " "} ${x.model.padEnd(14)} ${String(x.outputs).padStart(3)} outputs ${String(x.votes).padStart(3)} votes ${x.contenders.join(", ")} ${x.id}`
|
|
3989
|
+
)
|
|
3990
|
+
.join("\n")
|
|
3991
|
+
);
|
|
3992
|
+
return 0;
|
|
3993
|
+
}
|
|
3994
|
+
case "run": {
|
|
3995
|
+
const id = positionals[1];
|
|
3996
|
+
if (!id) throw new CliError("Usage: admin models run <id>");
|
|
3997
|
+
const result = await staffRequest(ctx, "GET", `${MODELS}/runs/${id}`);
|
|
3998
|
+
printResult(io, flags, result, (r) =>
|
|
3999
|
+
[
|
|
4000
|
+
`${r.model} · ${r.created_at} · ${JSON.stringify(r.input)}`,
|
|
4001
|
+
...(r.outputs ?? []).map(
|
|
4002
|
+
(o) =>
|
|
4003
|
+
` [${o.slot}] ${o.contender}${o.ours ? " (ours)" : ""}: ${o.error ? `error: ${o.error}` : Object.values(o.output).join(" — ")}`
|
|
4004
|
+
),
|
|
4005
|
+
].join("\n")
|
|
4006
|
+
);
|
|
4007
|
+
return 0;
|
|
4008
|
+
}
|
|
4009
|
+
case "star":
|
|
4010
|
+
case "unstar": {
|
|
4011
|
+
const id = positionals[1];
|
|
4012
|
+
if (!id) throw new CliError(`Usage: admin models ${sub} <id>`);
|
|
4013
|
+
const result = await staffRequest(ctx, "PATCH", `${MODELS}/runs/${id}`, { starred: sub === "star" });
|
|
4014
|
+
ok(ctx, `${sub === "star" ? "Starred" : "Unstarred"} ${result.id}`);
|
|
4015
|
+
printResult(io, flags, result, () => "");
|
|
4016
|
+
return 0;
|
|
4017
|
+
}
|
|
4018
|
+
case "scoreboard": {
|
|
4019
|
+
const model = flagStr(flags.model);
|
|
4020
|
+
if (!model) throw new CliError("Usage: admin models scoreboard --model ballpoint-1");
|
|
4021
|
+
const result = await staffRequest(
|
|
4022
|
+
ctx,
|
|
4023
|
+
"GET",
|
|
4024
|
+
`${MODELS}/arena/scoreboard?model=${encodeURIComponent(model)}`
|
|
4025
|
+
);
|
|
4026
|
+
printResult(io, flags, result, (r) =>
|
|
4027
|
+
(r.opponents ?? []).length
|
|
4028
|
+
? r.opponents
|
|
4029
|
+
.map(
|
|
4030
|
+
(o) =>
|
|
4031
|
+
`${r.model} vs ${o.opponent}: ${o.wins}-${o.losses} (${o.ties} ties, ${o.both_bad} both bad) · ${o.win_rate == null ? "—" : `${Math.round(o.win_rate * 100)}% [${Math.round(o.low * 100)}–${Math.round(o.high * 100)}]`} · ${o.voters} voters`
|
|
4032
|
+
)
|
|
4033
|
+
.join("\n")
|
|
4034
|
+
: `No votes on ${r.model} yet.`
|
|
4035
|
+
);
|
|
4036
|
+
return 0;
|
|
4037
|
+
}
|
|
4038
|
+
default:
|
|
4039
|
+
throw new CliError(MODELS_USAGE);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
4042
|
+
|
|
3965
4043
|
async function cmdAdminSpend(ctx) {
|
|
3966
4044
|
const { flags, positionals, io } = ctx;
|
|
3967
4045
|
const sub = positionals[0];
|
|
@@ -4043,7 +4121,34 @@ async function cmdAdminSpend(ctx) {
|
|
|
4043
4121
|
return 0;
|
|
4044
4122
|
}
|
|
4045
4123
|
case "usage": {
|
|
4046
|
-
|
|
4124
|
+
if (positionals[1] === "list") {
|
|
4125
|
+
// One source's calls back, newest first (GET /api/superadmin/spend/usage).
|
|
4126
|
+
const source = flagStr(flags.source);
|
|
4127
|
+
const from = flagStr(flags.from);
|
|
4128
|
+
const to = flagStr(flags.to);
|
|
4129
|
+
if (!source || !from || !to)
|
|
4130
|
+
throw new CliError(
|
|
4131
|
+
"Usage: admin spend usage list --source models --from YYYY-MM-DD --to YYYY-MM-DD [--limit N]"
|
|
4132
|
+
);
|
|
4133
|
+
const params = new URLSearchParams(
|
|
4134
|
+
compact({ source, from, to, limit: flagNum(flags.limit)?.toString() })
|
|
4135
|
+
);
|
|
4136
|
+
const result = await staffRequest(ctx, "GET", `${SPEND}/usage?${params}`);
|
|
4137
|
+
printResult(
|
|
4138
|
+
io,
|
|
4139
|
+
flags,
|
|
4140
|
+
result,
|
|
4141
|
+
(r) =>
|
|
4142
|
+
(r.events ?? [])
|
|
4143
|
+
.map(
|
|
4144
|
+
(e) =>
|
|
4145
|
+
`${e.occurred_at} ${e.model.padEnd(16)} ${e.operation.padEnd(10)} ${(e.outcome ?? "").padEnd(8)} ${String(e.latency_ms ?? "").padStart(7)}ms ${usd(e.cost_usd).padStart(9)} ${e.key_label}`
|
|
4146
|
+
)
|
|
4147
|
+
.join("\n") + (r.next ? "\n… more (narrow --from/--to or raise --limit)" : "")
|
|
4148
|
+
);
|
|
4149
|
+
return 0;
|
|
4150
|
+
}
|
|
4151
|
+
// Per-call model costs, as kernels / lettertrace / models push them (POST /api/superadmin/spend/usage):
|
|
4047
4152
|
// a JSON file holding { events: [...] } or a bare array. Idempotent on each event_id.
|
|
4048
4153
|
const path = positionals[1];
|
|
4049
4154
|
if (!path) throw new CliError("Usage: admin spend usage <events.json> ({ events: [...] } or an array)");
|
|
@@ -4193,7 +4298,7 @@ async function cmdAdminSpend(ctx) {
|
|
|
4193
4298
|
}
|
|
4194
4299
|
default:
|
|
4195
4300
|
throw new CliError(
|
|
4196
|
-
"Usage: admin spend summary [--range day|week|month|year | --from D --to D] [--grain day|week|month] | reconcile [--from D --to D] | pnl [--range …] | reference add … | stripe-sync --from D --to D | entries [--from D] [--to D] [--vendor V] [--area A] [--source S] | add --vendor V --amount N --from D … | import <file.csv> … | usage <events.json> | remove <entry-id> | services | service <slug> --owner … --monthly …"
|
|
4301
|
+
"Usage: admin spend summary [--range day|week|month|year | --from D --to D] [--grain day|week|month] | reconcile [--from D --to D] | pnl [--range …] | reference add … | stripe-sync --from D --to D | entries [--from D] [--to D] [--vendor V] [--area A] [--source S] | add --vendor V --amount N --from D … | import <file.csv> … | usage <events.json> | usage list --source S --from D --to D | remove <entry-id> | services | service <slug> --owner … --monthly …"
|
|
4197
4302
|
);
|
|
4198
4303
|
}
|
|
4199
4304
|
}
|
|
@@ -4740,6 +4845,7 @@ export async function cmdAdmin(ctx) {
|
|
|
4740
4845
|
return cmdAdminReplays({ ...ctx, positionals: ctx.positionals.slice(1) }, sub);
|
|
4741
4846
|
if (sub === "crm") return cmdAdminCrm({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
4742
4847
|
if (sub === "spend") return cmdAdminSpend({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
4848
|
+
if (sub === "models") return cmdAdminModels({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
4743
4849
|
if (sub === "create-org") return cmdAdminCreateOrg({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
4744
4850
|
if (sub === "ask") return cmdAdminAsk({ ...ctx, positionals: ctx.positionals.slice(1) });
|
|
4745
4851
|
if (sub === "patterns") return cmdAdminPatterns({ ...ctx, positionals: ctx.positionals.slice(1) });
|