@letterstory/cli 0.49.2 → 0.51.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 +14 -0
- package/lib/cli.mjs +1 -1
- package/lib/commands/arena.mjs +90 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -491,11 +491,25 @@ letterstory arena run-status <run-id> # status: awaiting_direct
|
|
|
491
491
|
letterstory arena direction <run-id> --choice 1
|
|
492
492
|
letterstory arena direction <run-id> --custom "Lead with the hidden costs"
|
|
493
493
|
letterstory arena direction <run-id> --skip # let the agents decide
|
|
494
|
+
letterstory arena run --topic "payroll solutions" --direction "Lead with the hidden costs" # no gate, no vote
|
|
495
|
+
|
|
496
|
+
# Watching runs (what an agent monitoring the account polls):
|
|
497
|
+
letterstory arena runs --status awaiting_direction # the gates waiting on you
|
|
498
|
+
letterstory arena runs --since 2026-10-02T00:00:00Z --limit 50
|
|
499
|
+
letterstory arena runs --before <next_cursor> # the next (older) page
|
|
500
|
+
letterstory arena latest --article <uuid> # the post's latest run, whoever started it
|
|
501
|
+
|
|
502
|
+
# What research decided each site is — and your call on one (research never overrides it):
|
|
503
|
+
letterstory arena roles --rival # competitors research found that you never listed
|
|
504
|
+
letterstory arena role set reviewsite.com --role context
|
|
505
|
+
letterstory arena role set rival.com --role company --company "Rival" --rival
|
|
506
|
+
letterstory arena role reset rival.com # hand it back to research
|
|
494
507
|
|
|
495
508
|
# Arenas are callable endpoints with one-file defaults (the org's default arena is "Letterstory"):
|
|
496
509
|
letterstory arena list
|
|
497
510
|
letterstory arena endpoint create --name "Docs research" --defaults '{"depth":"barebones"}'
|
|
498
511
|
letterstory arena endpoint config <arena-id> [--file cfg.json]
|
|
512
|
+
letterstory arena endpoint update <arena-id> --name "Docs research v2" # creator or org admin only
|
|
499
513
|
letterstory arena endpoint delete <arena-id> --yes
|
|
500
514
|
|
|
501
515
|
# Ledes: a prospect's context in, ready-to-send opening lines out (chosen from a
|
package/lib/cli.mjs
CHANGED
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
} from "./commands.mjs";
|
|
55
55
|
|
|
56
56
|
// Keep in sync with cli/package.json.
|
|
57
|
-
export const VERSION = "0.
|
|
57
|
+
export const VERSION = "0.51.0";
|
|
58
58
|
|
|
59
59
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
60
60
|
// can't accidentally swallow the id as --json's value.
|
package/lib/commands/arena.mjs
CHANGED
|
@@ -68,6 +68,8 @@ const RUN_OPTIONS = {
|
|
|
68
68
|
// --no-verify turns the fact-check off; nothing sent otherwise (the default is on).
|
|
69
69
|
verify: { value: (flags) => (flags["no-verify"] === true ? false : undefined) },
|
|
70
70
|
mention_degree: { flag: "mention", enum: ["off", "subtle", "woven"] },
|
|
71
|
+
// What the fact-check does with a claim it can neither fix nor stand behind: flag or remove it.
|
|
72
|
+
unresolved_claims: { flag: "unresolved", enum: ["comment", "drop"] },
|
|
71
73
|
// Positioning as data — a file, not flags: `--context-file ctx.json` of
|
|
72
74
|
// {manifesto, stances[], priority_topics[], avoid_topics[], identity{is[],is_not[],one_liner}}.
|
|
73
75
|
context: { value: (flags) => readJsonObjectFlag(flags, "context") },
|
|
@@ -116,6 +118,8 @@ export const ARGS = {
|
|
|
116
118
|
},
|
|
117
119
|
},
|
|
118
120
|
existing_content: { value: (flags) => flagStr(flags["existing-content"]) },
|
|
121
|
+
// Your own thesis: adopted as the run's direction, so a gate never pauses for it.
|
|
122
|
+
direction: { flag: "direction" },
|
|
119
123
|
article_id: { flag: "article" },
|
|
120
124
|
...RUN_OPTIONS,
|
|
121
125
|
},
|
|
@@ -124,8 +128,32 @@ export const ARGS = {
|
|
|
124
128
|
},
|
|
125
129
|
list_arena_runs: {
|
|
126
130
|
arena_id: { flag: "arena" },
|
|
131
|
+
article_id: { flag: "article" },
|
|
132
|
+
status: { flag: "status", type: "list" },
|
|
133
|
+
since: { flag: "since" },
|
|
134
|
+
before: { flag: "before" },
|
|
127
135
|
limit: { flag: "limit", type: "num" },
|
|
128
136
|
},
|
|
137
|
+
get_latest_arena_run: {
|
|
138
|
+
article_id: { flag: "article", required: true },
|
|
139
|
+
},
|
|
140
|
+
// What research decided each site is, and your call on one (never overridden by the model).
|
|
141
|
+
list_source_roles: {
|
|
142
|
+
role: { flag: "role", enum: ["authority", "company", "context"] },
|
|
143
|
+
rival: { flag: "rival", type: "bool" },
|
|
144
|
+
decided_by: { flag: "decided-by", enum: ["model", "customer", "staff"] },
|
|
145
|
+
limit: { flag: "limit", type: "num" },
|
|
146
|
+
},
|
|
147
|
+
set_source_role: {
|
|
148
|
+
site: { positional: 1, label: "site", required: true },
|
|
149
|
+
role: { flag: "role", enum: ["authority", "company", "context"], required: true },
|
|
150
|
+
company: { flag: "company" },
|
|
151
|
+
rival: { flag: "rival", type: "bool" },
|
|
152
|
+
note: { flag: "note" },
|
|
153
|
+
},
|
|
154
|
+
reset_source_role: {
|
|
155
|
+
site: { positional: 1, label: "site", required: true },
|
|
156
|
+
},
|
|
129
157
|
submit_arena_direction: {
|
|
130
158
|
run_id: { positional: 0, label: "run-id", required: true },
|
|
131
159
|
choice: { flag: "choice", type: "num" },
|
|
@@ -144,6 +172,11 @@ export const ARGS = {
|
|
|
144
172
|
delete_arena: {
|
|
145
173
|
arena_id: { positional: 1, label: "arena-id", required: true },
|
|
146
174
|
},
|
|
175
|
+
update_arena: {
|
|
176
|
+
arena_id: { positional: 1, label: "arena-id", required: true },
|
|
177
|
+
name: { flag: "name" },
|
|
178
|
+
defaults: { value: (flags) => readJsonObjectFlag(flags, "defaults") },
|
|
179
|
+
},
|
|
147
180
|
// The arena's configuration as ONE file: `arena endpoint config <id>` prints it,
|
|
148
181
|
// `arena endpoint config <id> --file cfg.json` replaces it with the file's document.
|
|
149
182
|
get_arena_config: {
|
|
@@ -167,6 +200,12 @@ export async function cmdArena(ctx) {
|
|
|
167
200
|
return arenaRunStatus(rest);
|
|
168
201
|
case "runs":
|
|
169
202
|
return arenaRuns(rest);
|
|
203
|
+
case "latest":
|
|
204
|
+
return arenaLatest(rest);
|
|
205
|
+
case "roles":
|
|
206
|
+
return arenaRoles(rest);
|
|
207
|
+
case "role":
|
|
208
|
+
return arenaRole(rest);
|
|
170
209
|
case "direction":
|
|
171
210
|
return arenaDirection(rest);
|
|
172
211
|
case "cancel":
|
|
@@ -181,7 +220,7 @@ export async function cmdArena(ctx) {
|
|
|
181
220
|
return arenaEndpoint(rest);
|
|
182
221
|
default:
|
|
183
222
|
throw new CliError(
|
|
184
|
-
`Unknown arena subcommand: ${sub ?? "(none)"}. Try: run, run-status, runs, direction, cancel, balance, list, endpoint`
|
|
223
|
+
`Unknown arena subcommand: ${sub ?? "(none)"}. Try: run, run-status, runs, latest, direction, cancel, balance, list, endpoint, roles, role`
|
|
185
224
|
);
|
|
186
225
|
}
|
|
187
226
|
}
|
|
@@ -262,6 +301,47 @@ async function arenaRuns(ctx) {
|
|
|
262
301
|
return 0;
|
|
263
302
|
}
|
|
264
303
|
|
|
304
|
+
async function arenaLatest(ctx) {
|
|
305
|
+
const { client, flags, io } = ctx;
|
|
306
|
+
const args = argsFromFlags(ARGS.get_latest_arena_run, flags, ctx.positionals);
|
|
307
|
+
const result = await client.callTool("get_latest_arena_run", args);
|
|
308
|
+
printResult(io, flags, result);
|
|
309
|
+
return 0;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function arenaRoles(ctx) {
|
|
313
|
+
const { client, flags, io } = ctx;
|
|
314
|
+
const result = await client.callTool(
|
|
315
|
+
"list_source_roles",
|
|
316
|
+
argsFromFlags(ARGS.list_source_roles, flags, ctx.positionals)
|
|
317
|
+
);
|
|
318
|
+
printResult(io, flags, result);
|
|
319
|
+
return 0;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** `arena role set <site> --role …` / `arena role reset <site>` — your call on one site. */
|
|
323
|
+
async function arenaRole(ctx) {
|
|
324
|
+
const { client, positionals, flags, io } = ctx;
|
|
325
|
+
const action = positionals[0];
|
|
326
|
+
if (action === "set") {
|
|
327
|
+
const args = argsFromFlags(ARGS.set_source_role, flags, positionals);
|
|
328
|
+
const result = await client.callTool("set_source_role", args);
|
|
329
|
+
ok(ctx, `${result?.role?.site ?? args.site} is now ${args.role}${args.rival ? " (a rival)" : ""}.`);
|
|
330
|
+
printResult(io, flags, result);
|
|
331
|
+
return 0;
|
|
332
|
+
}
|
|
333
|
+
if (action === "reset") {
|
|
334
|
+
const result = await client.callTool(
|
|
335
|
+
"reset_source_role",
|
|
336
|
+
argsFromFlags(ARGS.reset_source_role, flags, positionals)
|
|
337
|
+
);
|
|
338
|
+
ok(ctx, result?.reset ? "Handed back to research." : "Research had not recorded that site.");
|
|
339
|
+
printResult(io, flags, result);
|
|
340
|
+
return 0;
|
|
341
|
+
}
|
|
342
|
+
throw new CliError(`Unknown arena role action: ${action ?? "(none)"}. Try: set, reset`);
|
|
343
|
+
}
|
|
344
|
+
|
|
265
345
|
async function arenaDirection(ctx) {
|
|
266
346
|
const { client, flags, io } = ctx;
|
|
267
347
|
const runId = requirePositional(ctx.positionals, 0, "run-id");
|
|
@@ -327,6 +407,14 @@ async function arenaEndpoint(ctx) {
|
|
|
327
407
|
printResult(io, flags, result);
|
|
328
408
|
return 0;
|
|
329
409
|
}
|
|
410
|
+
if (action === "update" || action === "edit") {
|
|
411
|
+
const id = requirePositional(positionals, 1, "arena-id");
|
|
412
|
+
const args = argsFromFlags(ARGS.update_arena, flags, positionals);
|
|
413
|
+
const result = await client.callTool("update_arena", args);
|
|
414
|
+
ok(ctx, `Updated arena ${id}.`);
|
|
415
|
+
printResult(io, flags, result);
|
|
416
|
+
return 0;
|
|
417
|
+
}
|
|
330
418
|
if (action === "config") {
|
|
331
419
|
const id = requirePositional(positionals, 1, "arena-id");
|
|
332
420
|
if (flagStr(flags.file) === undefined) {
|
|
@@ -344,5 +432,5 @@ async function arenaEndpoint(ctx) {
|
|
|
344
432
|
printResult(io, flags, result);
|
|
345
433
|
return 0;
|
|
346
434
|
}
|
|
347
|
-
throw new CliError(`Unknown arena endpoint action: ${action ?? "(none)"}. Try: create, delete, config`);
|
|
435
|
+
throw new CliError(`Unknown arena endpoint action: ${action ?? "(none)"}. Try: create, update, delete, config`);
|
|
348
436
|
}
|