@letterstory/cli 0.66.0 → 0.69.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/README.md +9 -4
- package/lib/cli.mjs +22 -13
- package/lib/commands/admin.mjs +214 -10
- package/lib/commands/insights.mjs +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -369,14 +369,17 @@ letterstory admin tuning trial-run <trial> --repeats 2 # runs advance on the se
|
|
|
369
369
|
letterstory admin tuning trial-save <trial> --note "…" # a trial as a candidate version (never live); then `admin tuning compare`
|
|
370
370
|
letterstory admin tuning promote <experiment-id> --versions <service-kernel-id>:21 # from a concluded "ship" decision
|
|
371
371
|
letterstory admin experiments list --q colons # what we've tried
|
|
372
|
+
letterstory admin experiments list --primitive write --stage rarity # what we learned about one stage
|
|
373
|
+
letterstory admin experiments new "A different writer, voice rewritten, rarity rewrite off" --primitive write # an investigation in Write's notebook
|
|
372
374
|
letterstory admin experiments new "We use too many colons" --as "claude-code"
|
|
373
375
|
letterstory admin experiments update <id> --plan-file plan.json --budget 120
|
|
374
|
-
# ...a person approves the plan
|
|
376
|
+
# ...a person approves the plan on the investigation's page (approval gates spending a budget; a person's
|
|
377
|
+
# investigation needs none and is concluded straight away)...
|
|
375
378
|
letterstory admin experiments spend <id> 54
|
|
376
379
|
letterstory admin tuning-import lab/results/colons/publish/<brief>.json --experiment <id>
|
|
377
380
|
letterstory admin experiments conclude <id> --decision drop \
|
|
378
381
|
--conclusion "Colons fell 60%; P(machine) did not move; quality held." \
|
|
379
|
-
--evidence lab:"kernels lab/results/colons/report.md"
|
|
382
|
+
--evidence lab:"kernels lab/results/colons/report.md" --stages rules
|
|
380
383
|
```
|
|
381
384
|
|
|
382
385
|
The ledger behind Kernel Tuning's Experiments tab
|
|
@@ -728,8 +731,10 @@ AI visibility and page access — the Measure tabs' reads, for scripts and agent
|
|
|
728
731
|
```bash
|
|
729
732
|
# The Measure Overview: how often AI answers name you and cite your pages (rates
|
|
730
733
|
# with 95% intervals and gated trends), share of voice, search for your site and
|
|
731
|
-
# the phantom network kept apart, and each ranking target's standing.
|
|
732
|
-
|
|
734
|
+
# the phantom network kept apart, and each ranking target's standing. --part
|
|
735
|
+
# (repeatable) returns only those blocks: audience, ai, shareOfVoice, pageAccess,
|
|
736
|
+
# search, actions, targets — `ai` is the slow one on a large org.
|
|
737
|
+
letterstory insights summary [--period 14d|30d|90d] [--part <block>]...
|
|
733
738
|
|
|
734
739
|
# The AI Visibility Bank: which questions named you, cited your pages, or both (a
|
|
735
740
|
# breakthrough). All time unless --period; --source picks the phantom network
|
package/lib/cli.mjs
CHANGED
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
} from "./commands.mjs";
|
|
57
57
|
|
|
58
58
|
// Keep in sync with cli/package.json.
|
|
59
|
-
export const VERSION = "0.
|
|
59
|
+
export const VERSION = "0.69.0";
|
|
60
60
|
|
|
61
61
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
62
62
|
// can't accidentally swallow the id as --json's value.
|
|
@@ -554,19 +554,24 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
554
554
|
Live answer replays: breakthroughs re-asked in ChatGPT /
|
|
555
555
|
Gemini / Google / Perplexity / Claude, with screenshots.
|
|
556
556
|
Omit --org for the whole fleet. Needs fleet:read.
|
|
557
|
-
admin replay --org <uuid>
|
|
557
|
+
admin replay --org <uuid> [<response-id> | --target <uuid>] [--surface openai|anthropic|google-aio|google-gemini|perplexity]
|
|
558
558
|
Replay a breakthrough live now (background; poll
|
|
559
|
-
admin replays).
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
|
559
|
+
admin replays). With neither, the client's newest
|
|
560
|
+
breakthrough. Needs fleet:replay.
|
|
561
|
+
admin experiments list [--q colons] [--status proposed] [--primitive write] [--stage rarity] | show <id>
|
|
562
|
+
| new "<what you are investigating>" [--primitive write|research|shred|enhance] [--stages a,b]
|
|
563
|
+
[--hypothesis …] [--plan-file p.json] [--tags a,b] [--as "<agent>"]
|
|
564
|
+
| update <id> [--plan-file …] [--result-file …] [--evidence kind:ref,…] [--stages a,b] [--budget N]
|
|
563
565
|
| note|started <id> "<text>" | spend <id> <runs>
|
|
564
|
-
| conclude <id> --decision ship|drop|follow-up|inconclusive --conclusion "…" [--evidence …]
|
|
566
|
+
| conclude <id> --decision ship|drop|follow-up|inconclusive --conclusion "…" [--stages a,b] [--evidence …]
|
|
565
567
|
| abandon <id> --reason "…"
|
|
566
|
-
|
|
567
|
-
how, what it found and why
|
|
568
|
-
|
|
569
|
-
|
|
568
|
+
Each primitive's notebook of investigations:
|
|
569
|
+
what we tried, how, what it found and why,
|
|
570
|
+
and the pipeline stages it is about. A plan
|
|
571
|
+
is approved by a signed-in person before a
|
|
572
|
+
budget is spent; concluding needs evidence,
|
|
573
|
+
not approval. "ship" hands off: a promoter
|
|
574
|
+
makes it live. Needs tuning:experiment.
|
|
570
575
|
admin tuning-import <brief-results.json> [--experiment <id>]
|
|
571
576
|
One brief's kernels lab results as a console
|
|
572
577
|
session (a trial per arm), linked to its
|
|
@@ -630,7 +635,11 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
|
|
|
630
635
|
candidate, compare, comparisons, picks, pick,
|
|
631
636
|
reading-list, pair, side-by-side, promote,
|
|
632
637
|
sessions, session-new, propose, trial-add,
|
|
633
|
-
trial-run, trial-save,
|
|
638
|
+
trial-run, trial-save, the Write input bank
|
|
639
|
+
(inputs, input, inputs-harvest, input-save),
|
|
640
|
+
screens (screen-new, screens, screen,
|
|
641
|
+
screen-advance),
|
|
642
|
+
and the arena, shredder
|
|
634
643
|
and enhancer twins (every flag is listed in
|
|
635
644
|
cli/lib/commands/admin.mjs).
|
|
636
645
|
admin create-org --domain <bare-domain> [--name "Acme"] [--test] [--no-key]
|
|
@@ -882,7 +891,7 @@ Mail:
|
|
|
882
891
|
mail postal-address "<address>" Set the org's CAN-SPAM mailing address (email footers)
|
|
883
892
|
|
|
884
893
|
Insights:
|
|
885
|
-
insights summary [--period
|
|
894
|
+
insights summary [--period …] [--part <block>]... Measure Overview: AI named/cited rates, share of voice, search, targets
|
|
886
895
|
insights site [--period 14d|30d|90d] [--collection <uuid>]
|
|
887
896
|
insights post <article-id> [--period 14d|30d|90d]
|
|
888
897
|
insights top [--period 14d|30d|90d] [--collection <uuid>] [--limit <n>] [--sort clicks|impressions]
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// admin evals scoreboard|cases|runs|run|triage|guard|retire … (fleet:read / tuning:experiment)
|
|
12
12
|
// admin crm import|capture|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|record-churn|undo-churn|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (crm:read / crm:write)
|
|
13
13
|
// admin replays [--org <id>] [--target <id>] [--status …] [--limit n] (fleet:read)
|
|
14
|
-
// admin replay --org <id>
|
|
14
|
+
// admin replay --org <id> [<response-id> | --target <id>] [--surface …] (fleet:replay)
|
|
15
15
|
// admin create-org --domain acme.com [--name "Acme"] [--test] [--no-key] [--key-name N]
|
|
16
16
|
// [--capabilities a,b] [--onboard] [--about "…"] [--sitemap <url>]
|
|
17
17
|
// [--cms <provider>] [--posts N] [--seers suggest|skip] [--no-visuals]
|
|
@@ -268,7 +268,8 @@ function evidenceFrom(flags) {
|
|
|
268
268
|
|
|
269
269
|
function experimentLine(e) {
|
|
270
270
|
const decision = e.decision ? ` → ${e.decision}` : "";
|
|
271
|
-
|
|
271
|
+
const where = e.primitive ? `${e.primitive}${e.stages?.length ? `: ${e.stages.join(", ")}` : ""} ` : "";
|
|
272
|
+
return `${e.id} [${e.status}${decision}] ${where}${e.question}${e.gist ? `\n ${e.gist}` : ""}`;
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
/**
|
|
@@ -293,7 +294,13 @@ async function cmdAdminExperiments(ctx) {
|
|
|
293
294
|
switch (sub) {
|
|
294
295
|
case "list": {
|
|
295
296
|
const params = new URLSearchParams(
|
|
296
|
-
compact({
|
|
297
|
+
compact({
|
|
298
|
+
q: flagStr(flags.q),
|
|
299
|
+
status: flagStr(flags.status),
|
|
300
|
+
primitive: flagStr(flags.primitive),
|
|
301
|
+
stage: flagStr(flags.stage),
|
|
302
|
+
limit: flagStr(flags.limit),
|
|
303
|
+
})
|
|
297
304
|
);
|
|
298
305
|
const result = await staffRequest(ctx, "GET", `${EXPERIMENTS}?${params}`);
|
|
299
306
|
return out(result, (r) =>
|
|
@@ -306,9 +313,13 @@ async function cmdAdminExperiments(ctx) {
|
|
|
306
313
|
case "new": {
|
|
307
314
|
const question = [id, ...rest].filter(Boolean).join(" ").trim();
|
|
308
315
|
if (question.length < 3)
|
|
309
|
-
throw new CliError(
|
|
316
|
+
throw new CliError(
|
|
317
|
+
'Usage: admin experiments new "<what you are investigating>" [--primitive write|research|shred|enhance] [--stages write,rarity] [--plan-file plan.json] [--tags a,b]'
|
|
318
|
+
);
|
|
310
319
|
const body = compact({
|
|
311
320
|
question,
|
|
321
|
+
primitive: flagStr(flags.primitive),
|
|
322
|
+
stages: flagList(flags.stages),
|
|
312
323
|
restated: flagStr(flags.hypothesis),
|
|
313
324
|
plan: jsonFile(flags, "plan"),
|
|
314
325
|
method: flagStr(flags.method),
|
|
@@ -331,6 +342,7 @@ async function cmdAdminExperiments(ctx) {
|
|
|
331
342
|
result: jsonFile(flags, "result"),
|
|
332
343
|
method: flagStr(flags.method),
|
|
333
344
|
tags: flagList(flags.tags),
|
|
345
|
+
stages: flagList(flags.stages),
|
|
334
346
|
budget_runs: flagNum(flags.budget),
|
|
335
347
|
engine_build: flagStr(flags.build),
|
|
336
348
|
add_evidence: evidenceFrom(flags),
|
|
@@ -357,12 +369,13 @@ async function cmdAdminExperiments(ctx) {
|
|
|
357
369
|
const conclusion = flagStr(flags.conclusion);
|
|
358
370
|
if (!id || !decision || !conclusion)
|
|
359
371
|
throw new CliError(
|
|
360
|
-
'Usage: admin experiments conclude <id> --decision ship|drop|follow-up|inconclusive --conclusion "<what we learned and why>" [--evidence kind:ref,…] [--result-file r.json]'
|
|
372
|
+
'Usage: admin experiments conclude <id> --decision ship|drop|follow-up|inconclusive --conclusion "<what we learned and why>" [--stages write,rarity] [--evidence kind:ref,…] [--result-file r.json]'
|
|
361
373
|
);
|
|
362
374
|
const body = compact({
|
|
363
375
|
action: "conclude",
|
|
364
376
|
decision,
|
|
365
377
|
conclusion,
|
|
378
|
+
stages: flagList(flags.stages),
|
|
366
379
|
result: jsonFile(flags, "result"),
|
|
367
380
|
add_evidence: evidenceFrom(flags),
|
|
368
381
|
actor: actorFrom(flags),
|
|
@@ -443,13 +456,28 @@ async function cmdAdminTuningContext(ctx) {
|
|
|
443
456
|
* admin tuning base-kernels the kernels a session can run on (ids for --kernel)
|
|
444
457
|
* admin tuning base-versions <kernel-id> the versions a session on it can run against
|
|
445
458
|
* admin tuning sessions | session <id> [--texts] list / one session: trials, runs and their numbers (--texts adds each trial's latest text)
|
|
446
|
-
* admin tuning session-new --title "…" --kernel <id|name> (--input-file f.md | --input "…") [--kind article|outline|brief]
|
|
459
|
+
* admin tuning session-new --title "…" --kernel <id|name> (--input-file f.md | --input "…" | --bank <input-id>) [--kind article|outline|brief]
|
|
447
460
|
* [--version N] [--writers echo/echo,…] [--trials-from <session-id>]
|
|
461
|
+
* (--bank: a bank input's text, and its request's constraints under every trial)
|
|
448
462
|
* admin tuning propose <session-id> --text "Echo with rarity on; live with the shred after" [--create]
|
|
449
463
|
* admin tuning trial-add <session-id> [--name "…"] [--patch '{…}'] [--options '{…}'] [--from <trial-id>]
|
|
450
464
|
* admin tuning trial-run <trial-id> [--repeats 2] queue runs (guardrails apply)
|
|
451
465
|
* admin tuning trial-save <trial-id> [--note "…"] save a trial as a candidate version (never live)
|
|
452
466
|
*
|
|
467
|
+
* The Write input bank: real kernel requests (above all the arena outlines Auto-Pen sends), as sent.
|
|
468
|
+
* admin tuning inputs [--filter "origin=arena_outline;material=thin,typical"] [--q "…"] list by tag, with coverage per bucket
|
|
469
|
+
* admin tuning input <input-id> one input in full: text, constraints, tags, run defaults, origin
|
|
470
|
+
* admin tuning inputs-harvest [--n 40] [--pool 400] [--callers auto-pen,endpoint] [--since-days 21] [--min-per-bucket 3]
|
|
471
|
+
* freeze recent production runs, stratified; idempotent by key
|
|
472
|
+
* admin tuning input-save <session-id> [--note "…"] save a session's pasted input or arena outline to the bank
|
|
473
|
+
*
|
|
474
|
+
* Screens: "is this candidate worth a full comparison?", on a slice of the bank (it does not decide).
|
|
475
|
+
* admin tuning screen-new --title "…" (--from <session-id> | --kernel <kernel-id> --versions 23,29) [--version N]
|
|
476
|
+
* [--n 8] [--filter "origin=arena_outline;material=thin"] [--inputs <id>,…] [--repeats 1] [--lift-budget]
|
|
477
|
+
* one session per input with the same trials; runs queue as the console's caps allow
|
|
478
|
+
* admin tuning screens | screen <id> list / one screen: per candidate, each measure against the Base, with its noise
|
|
479
|
+
* admin tuning screen-advance <id> queue what the caps allow now (the cron does it every minute)
|
|
480
|
+
*
|
|
453
481
|
* Research (Phase 3): our arena's versions as files, research comparisons, the deploy split.
|
|
454
482
|
* admin tuning arenas | arena <version-id> our arena's versions / one version's file and diff
|
|
455
483
|
* admin tuning arena-candidate --patch '{…}' | --file f.json [--of <version-id>] [--note "…"] save a candidate
|
|
@@ -492,6 +520,19 @@ function jsonFlag(raw, name) {
|
|
|
492
520
|
}
|
|
493
521
|
}
|
|
494
522
|
|
|
523
|
+
/**
|
|
524
|
+
* `--filter "origin=arena_outline;material=thin,typical"` → the bank's query params (one comma list
|
|
525
|
+
* per tag dimension; lib/tuning/input-tags.ts `parseTagFilter` reads the same form).
|
|
526
|
+
*/
|
|
527
|
+
function tagFilterParams(raw) {
|
|
528
|
+
const out = {};
|
|
529
|
+
for (const part of (raw ?? "").split(";")) {
|
|
530
|
+
const [k, v] = part.split("=");
|
|
531
|
+
if (k?.trim() && v?.trim()) out[k.trim()] = v.trim();
|
|
532
|
+
}
|
|
533
|
+
return out;
|
|
534
|
+
}
|
|
535
|
+
|
|
495
536
|
/**
|
|
496
537
|
* A session as an agent reads it: each trial's changes and runs with their headline numbers, and
|
|
497
538
|
* (with `texts`) the latest finished text per trial. The full session (traces, records) is `--json`.
|
|
@@ -770,9 +811,11 @@ async function cmdAdminTuning(ctx) {
|
|
|
770
811
|
throw new CliError(`--input-file ${path}: ${err.message}`);
|
|
771
812
|
}
|
|
772
813
|
}
|
|
773
|
-
|
|
814
|
+
// A bank input instead of a paste: its text, and its request's constraints under every trial.
|
|
815
|
+
const bank = flagStr(flags.bank);
|
|
816
|
+
if (!title || !kernel || (!input && !bank))
|
|
774
817
|
throw new CliError(
|
|
775
|
-
'Usage: admin tuning session-new --title "…" --kernel <id|name> (--input-file f.md | --input "…") [--kind article|outline|brief] [--version N] [--writers a,b] [--versions 23,29] [--trials-from <session-id>]'
|
|
818
|
+
'Usage: admin tuning session-new --title "…" --kernel <id|name> (--input-file f.md | --input "…" | --bank <input-id>) [--kind article|outline|brief] [--version N] [--writers a,b] [--versions 23,29] [--trials-from <session-id>]'
|
|
776
819
|
);
|
|
777
820
|
let kernelId = kernel;
|
|
778
821
|
if (!/^[0-9a-f-]{36}$/i.test(kernel)) {
|
|
@@ -788,8 +831,9 @@ async function cmdAdminTuning(ctx) {
|
|
|
788
831
|
T,
|
|
789
832
|
compact({
|
|
790
833
|
title,
|
|
791
|
-
input_text: input,
|
|
834
|
+
input_text: bank ? undefined : input,
|
|
792
835
|
input_kind: flagStr(flags.kind) ?? "unknown",
|
|
836
|
+
material: bank ? { source: "bank", input_id: bank } : undefined,
|
|
793
837
|
base_kernel_id: kernelId,
|
|
794
838
|
base_version: flagNum(flags.version),
|
|
795
839
|
trials_from_session_id: flagStr(flags["trials-from"]),
|
|
@@ -871,6 +915,167 @@ async function cmdAdminTuning(ctx) {
|
|
|
871
915
|
`${r.kernel}: saved as candidate v${r.version}${r.baseVersion ? ` (from v${r.baseVersion})` : ""}${r.leftBehind.length ? `; per-run, not saved: ${r.leftBehind.join(", ")}` : ""}`
|
|
872
916
|
);
|
|
873
917
|
}
|
|
918
|
+
// --- The Write input bank: real kernel requests a session can start from ---
|
|
919
|
+
case "inputs": {
|
|
920
|
+
const q = new URLSearchParams(
|
|
921
|
+
compact({ ...tagFilterParams(flagStr(flags.filter)), q: flagStr(flags.q), limit: flagStr(flags.limit) })
|
|
922
|
+
);
|
|
923
|
+
const r = await staffRequest(ctx, "GET", `${T}/inputs${q.size ? `?${q}` : ""}`);
|
|
924
|
+
if (json) return printResult(io, flags, r);
|
|
925
|
+
const coverage = Object.entries(r.coverage)
|
|
926
|
+
.map(
|
|
927
|
+
([dim, buckets]) =>
|
|
928
|
+
` ${dim.padEnd(11)} ${Object.entries(buckets)
|
|
929
|
+
.map(([b, n]) => `${b} ${n}`)
|
|
930
|
+
.join(" · ")}`
|
|
931
|
+
)
|
|
932
|
+
.join("\n");
|
|
933
|
+
return io.log(
|
|
934
|
+
[
|
|
935
|
+
`bank ${r.set}: ${r.inputs.length} of ${r.total} input(s)`,
|
|
936
|
+
...r.inputs.map(
|
|
937
|
+
(i) =>
|
|
938
|
+
`${i.id} ${i.source.padEnd(10)} ${String(i.tags.origin ?? "").padEnd(13)} ${String(i.tags.material?.bucket ?? "").padEnd(7)} ${String(i.tags.shape?.bucket ?? "").padEnd(5)} ${i.title}`
|
|
939
|
+
),
|
|
940
|
+
"coverage (the whole bank):",
|
|
941
|
+
coverage,
|
|
942
|
+
].join("\n")
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
case "input": {
|
|
946
|
+
if (!id) throw new CliError("Usage: admin tuning input <input-id>");
|
|
947
|
+
return printResult(io, { ...flags, json: true }, await staffRequest(ctx, "GET", `${T}/inputs/${id}`));
|
|
948
|
+
}
|
|
949
|
+
case "inputs-harvest": {
|
|
950
|
+
const r = await staffRequest(
|
|
951
|
+
ctx,
|
|
952
|
+
"POST",
|
|
953
|
+
`${T}/inputs/harvest`,
|
|
954
|
+
compact({
|
|
955
|
+
n: flagNum(flags.n),
|
|
956
|
+
pool: flagNum(flags.pool),
|
|
957
|
+
callers: flagStr(flags.callers)
|
|
958
|
+
?.split(",")
|
|
959
|
+
.map((c) => c.trim())
|
|
960
|
+
.filter(Boolean),
|
|
961
|
+
since_days: flagNum(flags["since-days"]),
|
|
962
|
+
min_per_bucket: flagNum(flags["min-per-bucket"]),
|
|
963
|
+
})
|
|
964
|
+
);
|
|
965
|
+
if (json) return printResult(io, flags, r);
|
|
966
|
+
return io.log(
|
|
967
|
+
[
|
|
968
|
+
`added ${r.added.length} input(s) to ${r.set} from a pool of ${r.pool} run(s); ${r.alreadyHeld} already held`,
|
|
969
|
+
...r.added.map((a) => ` ${a.key} (${a.reason})`),
|
|
970
|
+
...Object.entries(r.skipped).map(([why, n]) => ` skipped ${n}: ${why}`),
|
|
971
|
+
].join("\n")
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
case "input-save": {
|
|
975
|
+
if (!id) throw new CliError('Usage: admin tuning input-save <session-id> [--note "…"]');
|
|
976
|
+
const r = await staffRequest(
|
|
977
|
+
ctx,
|
|
978
|
+
"POST",
|
|
979
|
+
`${T}/sessions/${id}/bank`,
|
|
980
|
+
compact({ note: flagStr(flags.note) })
|
|
981
|
+
);
|
|
982
|
+
return json ? printResult(io, flags, r) : io.log(`bank input ${r.input.id} (${r.input.key})`);
|
|
983
|
+
}
|
|
984
|
+
// --- Screens: candidates across a slice of the bank, read against the Base, beside the noise ---
|
|
985
|
+
case "screen-new": {
|
|
986
|
+
const title = flagStr(flags.title);
|
|
987
|
+
const from = flagStr(flags.from);
|
|
988
|
+
const versions = (flagStr(flags.versions) ?? "")
|
|
989
|
+
.split(",")
|
|
990
|
+
.map((v) => Number(v.trim()))
|
|
991
|
+
.filter((v) => Number.isInteger(v) && v > 0);
|
|
992
|
+
if (!title || (!from && !(flagStr(flags.kernel) && versions.length)))
|
|
993
|
+
throw new CliError(
|
|
994
|
+
'Usage: admin tuning screen-new --title "…" (--from <session-id> | --kernel <kernel-id> --versions 23,29) [--version N] [--n 8] [--filter "origin=arena_outline;material=thin"] [--inputs <id>,…] [--repeats 1] [--lift-budget]'
|
|
995
|
+
);
|
|
996
|
+
const filter = Object.fromEntries(
|
|
997
|
+
Object.entries(tagFilterParams(flagStr(flags.filter))).map(([k, v]) => [
|
|
998
|
+
k,
|
|
999
|
+
v
|
|
1000
|
+
.split(",")
|
|
1001
|
+
.map((x) => x.trim())
|
|
1002
|
+
.filter(Boolean),
|
|
1003
|
+
])
|
|
1004
|
+
);
|
|
1005
|
+
const inputIds = (flagStr(flags.inputs) ?? "")
|
|
1006
|
+
.split(",")
|
|
1007
|
+
.map((x) => x.trim())
|
|
1008
|
+
.filter(Boolean);
|
|
1009
|
+
const r = await staffRequest(
|
|
1010
|
+
ctx,
|
|
1011
|
+
"POST",
|
|
1012
|
+
`${T}/screens`,
|
|
1013
|
+
compact({
|
|
1014
|
+
title,
|
|
1015
|
+
from_session_id: from,
|
|
1016
|
+
base_kernel_id: flagStr(flags.kernel),
|
|
1017
|
+
base_version: flagNum(flags.version),
|
|
1018
|
+
versions: versions.length ? versions : undefined,
|
|
1019
|
+
n: flagNum(flags.n),
|
|
1020
|
+
filter: Object.keys(filter).length ? filter : undefined,
|
|
1021
|
+
input_ids: inputIds.length ? inputIds : undefined,
|
|
1022
|
+
repeats: flagNum(flags.repeats),
|
|
1023
|
+
lift_budget: flagBool(flags["lift-budget"]) || undefined,
|
|
1024
|
+
})
|
|
1025
|
+
);
|
|
1026
|
+
if (json) return printResult(io, flags, r);
|
|
1027
|
+
return io.log(
|
|
1028
|
+
`screen ${r.screen.id}: ${r.screen.inputs} input(s), ${r.aggregate.columns.length} column(s); ${r.screen.pending} run(s) waiting${r.screen.waiting ? ` (${r.screen.waiting})` : ""} → ${ctx.client.url}/superadmin/tuning/screens/${r.screen.id}`
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
case "screens": {
|
|
1032
|
+
const r = await staffRequest(ctx, "GET", `${T}/screens?limit=${flagNum(flags.limit) ?? 30}`);
|
|
1033
|
+
if (json) return printResult(io, flags, r);
|
|
1034
|
+
return io.log(
|
|
1035
|
+
r.screens
|
|
1036
|
+
.map(
|
|
1037
|
+
(x) =>
|
|
1038
|
+
`${x.id} ${x.status.padEnd(7)} ${x.title} · ${x.inputs} inputs${x.pending ? ` · ${x.pending} waiting` : ""}`
|
|
1039
|
+
)
|
|
1040
|
+
.join("\n") || "(no screens)"
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
case "screen": {
|
|
1044
|
+
if (!id) throw new CliError("Usage: admin tuning screen <screen-id>");
|
|
1045
|
+
const r = await staffRequest(ctx, "GET", `${T}/screens/${id}`);
|
|
1046
|
+
if (json) return printResult(io, flags, r);
|
|
1047
|
+
// The reading as an agent reads it: per candidate, each measure's difference from the Base and its noise.
|
|
1048
|
+
return printResult(
|
|
1049
|
+
io,
|
|
1050
|
+
{ ...flags, json: true },
|
|
1051
|
+
{
|
|
1052
|
+
screen: r.screen,
|
|
1053
|
+
note: r.aggregate.note,
|
|
1054
|
+
columns: r.aggregate.columns,
|
|
1055
|
+
measures: r.aggregate.measures.map((m) => ({
|
|
1056
|
+
measure: m.label,
|
|
1057
|
+
judge: m.judgeId,
|
|
1058
|
+
standing: m.standing,
|
|
1059
|
+
sigma: m.sigma,
|
|
1060
|
+
per_column: m.perTrial.map((p) =>
|
|
1061
|
+
compact({
|
|
1062
|
+
column: p.column,
|
|
1063
|
+
n: p.n,
|
|
1064
|
+
mean: p.mean,
|
|
1065
|
+
delta: p.delta ?? undefined,
|
|
1066
|
+
})
|
|
1067
|
+
),
|
|
1068
|
+
})),
|
|
1069
|
+
}
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
case "screen-advance": {
|
|
1073
|
+
if (!id) throw new CliError("Usage: admin tuning screen-advance <screen-id>");
|
|
1074
|
+
const r = await staffRequest(ctx, "POST", `${T}/screens/${id}/advance`, {});
|
|
1075
|
+
return json
|
|
1076
|
+
? printResult(io, flags, r)
|
|
1077
|
+
: io.log(`queued ${r.queued} run(s)${r.waiting ? `; waiting: ${r.waiting}` : ""}`);
|
|
1078
|
+
}
|
|
874
1079
|
// --- Research: our arena's versions, research comparisons, the deploy split ---
|
|
875
1080
|
case "arenas": {
|
|
876
1081
|
const r = await staffRequest(ctx, "GET", `${T}/arena-files`);
|
|
@@ -1977,7 +2182,6 @@ async function cmdAdminReplays(ctx, sub) {
|
|
|
1977
2182
|
const responseId = positionals[0];
|
|
1978
2183
|
const target = flagStr(flags.target);
|
|
1979
2184
|
if (!org) throw new CliError("admin replay needs --org <org-id>");
|
|
1980
|
-
if (!responseId && !target) throw new CliError("Pass a breakthrough <response-id>, or --target <target-id>");
|
|
1981
2185
|
const result = await staffPost(
|
|
1982
2186
|
ctx,
|
|
1983
2187
|
REPLAYS,
|