@letterstory/cli 0.33.11 → 0.35.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 +8 -2
- package/lib/cli.mjs +10 -5
- package/lib/commands/autopen.mjs +2 -1
- package/lib/commands/kernel.mjs +21 -36
- package/lib/commands/phantom.mjs +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -389,10 +389,16 @@ letterstory lede endpoint config <endpoint-id> [--file cfg.json]
|
|
|
389
389
|
|
|
390
390
|
# 2. Have a kernel write the draft
|
|
391
391
|
letterstory kernel list
|
|
392
|
-
letterstory kernel
|
|
392
|
+
letterstory kernel write <endpoint-id> --article <uuid> [--kernel <uuid>] [--file brief.md]
|
|
393
393
|
letterstory kernel status <kernel-job-id>
|
|
394
394
|
```
|
|
395
395
|
|
|
396
|
+
`kernel run` (and the `submit_kernel_run` tool behind it) was removed on 2026-09-27. Its one
|
|
397
|
+
job is `kernel write <endpoint-id> --article <uuid>`: with no `--body`/`--file` it writes from
|
|
398
|
+
the article's own content, and `kernel status` still polls the job it starts. Its
|
|
399
|
+
`--brief`/`--brief-file` flags have no replacement: the input is `--body`/`--file`, and
|
|
400
|
+
guidance that is not content goes in `--directives`.
|
|
401
|
+
|
|
396
402
|
### The standalone kernel endpoint
|
|
397
403
|
|
|
398
404
|
`kernel write` and `kernel polish` hit the standalone door: prose comes back, nothing is
|
|
@@ -403,7 +409,7 @@ letterstory kernel endpoint create --name "Writer"
|
|
|
403
409
|
letterstory kernel endpoint delete <endpoint-id> --yes
|
|
404
410
|
|
|
405
411
|
letterstory kernel write <endpoint-id> --file outline.md \
|
|
406
|
-
--
|
|
412
|
+
--read-as outline --person first --author "Ada" --shredder <endpoint-id>
|
|
407
413
|
# Follows the run and prints the ARTICLE when it lands. --no-wait returns the run id instead.
|
|
408
414
|
```
|
|
409
415
|
|
package/lib/cli.mjs
CHANGED
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
} from "./commands.mjs";
|
|
46
46
|
|
|
47
47
|
// Keep in sync with cli/package.json.
|
|
48
|
-
export const VERSION = "0.
|
|
48
|
+
export const VERSION = "0.35.0";
|
|
49
49
|
|
|
50
50
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
51
51
|
// can't accidentally swallow the id as --json's value.
|
|
@@ -84,6 +84,8 @@ const BOOLEAN_FLAGS = new Set([
|
|
|
84
84
|
"no-visuals",
|
|
85
85
|
"no-enhance",
|
|
86
86
|
"no-key",
|
|
87
|
+
// `autopen start --article <id> --from-scratch`
|
|
88
|
+
"from-scratch",
|
|
87
89
|
// `collections activate <id> --no-topic-map` / `--no-headlines`
|
|
88
90
|
"no-topic-map",
|
|
89
91
|
"no-headlines",
|
|
@@ -319,8 +321,9 @@ Arenas (adversarial clusters of research agents -> a sourced, fact-checked outli
|
|
|
319
321
|
arena endpoint delete <arena-id> --yes
|
|
320
322
|
|
|
321
323
|
Auto-Pen (research -> kernel -> Enhance, in one run — and the ONLY path that
|
|
322
|
-
applies a collection's content template; kernel
|
|
324
|
+
applies a collection's content template; kernel write --article does not):
|
|
323
325
|
autopen start --article <uuid> Start the run; takes 10-40 min
|
|
326
|
+
autopen start --article <uuid> --from-scratch Clear the draft first, then run
|
|
324
327
|
autopen status --article <uuid> Step states + the template in use
|
|
325
328
|
autopen cancel --article <uuid> --yes Stop a run in flight
|
|
326
329
|
|
|
@@ -337,9 +340,11 @@ Writing kernels (kernels write the draft; they do not research — run research
|
|
|
337
340
|
kernel list List available writing kernels
|
|
338
341
|
|
|
339
342
|
Into an article you already have (metered on the AI-usage gate):
|
|
340
|
-
kernel
|
|
341
|
-
|
|
342
|
-
|
|
343
|
+
kernel write <endpoint-id> --article <uuid> [--kernel <uuid>] [--body <text>|--file <path>]
|
|
344
|
+
Write into the article (from its own
|
|
345
|
+
content when no input is given);
|
|
346
|
+
takes 15-20 min
|
|
347
|
+
kernel status <kernel-job-id> Check that run's status
|
|
343
348
|
|
|
344
349
|
Standalone — prose back, nothing saved into an article (metered in kernel-run credits):
|
|
345
350
|
kernel endpoints Your kernel endpoints
|
package/lib/commands/autopen.mjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
// This is the command that makes a TEMPLATE take effect. A template bound with
|
|
5
5
|
// `collections autopen <id> --template-key <key>` is read inside the Auto-Pen run and
|
|
6
|
-
// nowhere else, so `kernel
|
|
6
|
+
// nowhere else, so `kernel write --article` (which hands the draft's current text straight to a
|
|
7
7
|
// kernel) will not produce a templated post no matter how the collection is configured.
|
|
8
8
|
//
|
|
9
9
|
// A run takes 10-40 minutes, so `start` returns as soon as it is queued. `status` both
|
|
@@ -17,6 +17,7 @@ import { flagBool, requireFlag, printResult, ok, argsFromFlags } from "./shared.
|
|
|
17
17
|
export const ARGS = {
|
|
18
18
|
run_auto_pen: {
|
|
19
19
|
article_id: { flag: "article", required: true },
|
|
20
|
+
from_scratch: { flag: "from-scratch", type: "bool" },
|
|
20
21
|
},
|
|
21
22
|
};
|
|
22
23
|
|
package/lib/commands/kernel.mjs
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
// TWO PRODUCTS SHARE THIS NOUN, and the subcommands are split along that line because
|
|
4
4
|
// confusing them wastes fifteen minutes and a credit:
|
|
5
5
|
//
|
|
6
|
-
// kernel run/status writes INTO an article you already have (submit_kernel_run).
|
|
7
|
-
// Metered on the AI-usage gate; needs --article.
|
|
8
6
|
// kernel write/… the STANDALONE endpoint (run_kernel) — you get prose back and
|
|
9
7
|
// nothing is saved into an article. Metered in kernel-run
|
|
10
8
|
// credits, the balance the Kernels page shows.
|
|
9
|
+
// kernel write --article the same tool writing INTO an article you already have (with no
|
|
10
|
+
// + kernel status input, from the article's own content). Metered on the AI-usage
|
|
11
|
+
// gate; follow it with `kernel status <kernel-job-id>`. This
|
|
12
|
+
// replaced `kernel run` (and its tool) on 2026-09-27.
|
|
11
13
|
//
|
|
12
14
|
// The standalone door had MCP tools and no CLI at all, so the only way to reach the product
|
|
13
15
|
// the Kernels page bills for was `letterstory mcp call run_kernel` with hand-written JSON.
|
|
@@ -85,21 +87,6 @@ function variablesFromFlags(flags) {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
export const ARGS = {
|
|
88
|
-
// The article-bound door: submit a kernel run INTO an article you already have.
|
|
89
|
-
submit_kernel_run: {
|
|
90
|
-
article_id: { flag: "article", required: true },
|
|
91
|
-
kernel_id: { flag: "kernel", required: true },
|
|
92
|
-
// A brief overrides the article's own content as the instruction; --brief-file reads
|
|
93
|
-
// it from a path. Omit both to write from the article as it stands.
|
|
94
|
-
brief: { value: (flags) => flagStr(flags.brief) ?? readBodyInput({ file: flagStr(flags["brief-file"]) }) },
|
|
95
|
-
// How to read --brief: auto (default) treats a short topic as instruction and a pasted
|
|
96
|
-
// draft/article as source material to decompose first — your own finished post is
|
|
97
|
-
// `article`. Same flag name as run_kernel's.
|
|
98
|
-
content_kind: {
|
|
99
|
-
flag: "read-as",
|
|
100
|
-
enum: ["auto", "instruction", "document", "article", "outline", "research", "notes"],
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
90
|
// The standalone door. Two subcommands share this one tool: `write` and `polish` both
|
|
104
91
|
// send `input`, `polish` defaulting content_kind to "article" — the map is one, so a field
|
|
105
92
|
// the tool gains is a field BOTH subcommands must learn (or knowingly gap) — that is the
|
|
@@ -111,14 +98,14 @@ export const ARGS = {
|
|
|
111
98
|
target_word_count: { flag: "words", type: "num" },
|
|
112
99
|
target_word_tolerance: { flag: "words-tolerance", type: "num" },
|
|
113
100
|
// Write into an article instead of handing the text back (2026-09-27): the one call that
|
|
114
|
-
//
|
|
115
|
-
//
|
|
101
|
+
// replaced `kernel run`. With `--article` and no input, the article's own content is the
|
|
102
|
+
// input.
|
|
116
103
|
article_id: { flag: "article" },
|
|
117
104
|
label: "label",
|
|
118
105
|
// The flag is --read-as, which is what shipped; an earlier draft called it --brief-mode.
|
|
119
106
|
content_kind: {
|
|
120
107
|
flag: "read-as",
|
|
121
|
-
enum: ["auto", "instruction", "
|
|
108
|
+
enum: ["auto", "instruction", "article", "outline", "research", "notes"],
|
|
122
109
|
},
|
|
123
110
|
// The two products, in one run: every round is shredded before the kernel's jury sees
|
|
124
111
|
// it, so the verdict lands on the text that actually ships. Costs a shred as well as a
|
|
@@ -159,8 +146,6 @@ export const ARGS = {
|
|
|
159
146
|
object: {
|
|
160
147
|
tier: { flag: "shred-tier", enum: ["cheap", "mid", "strong", "frontier"] },
|
|
161
148
|
families: { flag: "shred-family", type: "list" },
|
|
162
|
-
revise_shredded: { flag: "shred-revise", type: "bool" },
|
|
163
|
-
revision_model: "shred-revision-model",
|
|
164
149
|
skip_voice_bearing: { flag: "shred-skip-voice-bearing", type: "bool" },
|
|
165
150
|
judge: { flag: "shred-judge", type: "bool" },
|
|
166
151
|
attempts_per_unit: { flag: "shred-attempts", type: "num" },
|
|
@@ -248,8 +233,6 @@ export async function cmdKernel(ctx) {
|
|
|
248
233
|
case "list":
|
|
249
234
|
case "ls":
|
|
250
235
|
return kernelList(rest);
|
|
251
|
-
case "run":
|
|
252
|
-
return kernelRun(rest);
|
|
253
236
|
case "status":
|
|
254
237
|
return kernelStatus(rest);
|
|
255
238
|
case "endpoints":
|
|
@@ -274,7 +257,7 @@ export async function cmdKernel(ctx) {
|
|
|
274
257
|
return kernelBalance(rest);
|
|
275
258
|
default:
|
|
276
259
|
throw new CliError(
|
|
277
|
-
`Unknown kernel subcommand: ${sub ?? "(none)"}. Try: list, endpoints, endpoint, eval, update, archive, write, polish, run-status, runs, balance,
|
|
260
|
+
`Unknown kernel subcommand: ${sub ?? "(none)"}. Try: list, endpoints, endpoint, eval, update, archive, write, polish, run-status, runs, balance, status`
|
|
278
261
|
);
|
|
279
262
|
}
|
|
280
263
|
}
|
|
@@ -286,15 +269,6 @@ async function kernelList(ctx) {
|
|
|
286
269
|
return 0;
|
|
287
270
|
}
|
|
288
271
|
|
|
289
|
-
async function kernelRun(ctx) {
|
|
290
|
-
const { client, flags, io } = ctx;
|
|
291
|
-
const args = argsFromFlags(ARGS.submit_kernel_run, flags, ctx.positionals);
|
|
292
|
-
const result = await client.callTool("submit_kernel_run", args);
|
|
293
|
-
ok(ctx, `Kernel run started. Check progress with: kernel status ${result?.kernel_job_id ?? "<kernel-job-id>"}`);
|
|
294
|
-
printResult(io, flags, result);
|
|
295
|
-
return 0;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
272
|
async function kernelStatus(ctx) {
|
|
299
273
|
const { client, positionals, flags, io } = ctx;
|
|
300
274
|
const jobId = requirePositional(positionals, 0, "kernel-job-id");
|
|
@@ -358,10 +332,21 @@ async function kernelEndpoints(ctx) {
|
|
|
358
332
|
async function kernelWrite(ctx) {
|
|
359
333
|
const { client, positionals, flags, io } = ctx;
|
|
360
334
|
const args = argsFromFlags(ARGS.run_kernel, flags, positionals);
|
|
361
|
-
|
|
362
|
-
|
|
335
|
+
// With --article the article's own content is the input, so only a standalone write needs one.
|
|
336
|
+
if (args.input === undefined && args.article_id === undefined) {
|
|
337
|
+
throw new CliError(
|
|
338
|
+
"Provide the brief with --body <text>, --file <path>, or --file - (stdin), or --article <uuid> to write from that article."
|
|
339
|
+
);
|
|
363
340
|
}
|
|
364
341
|
const result = await client.callTool("run_kernel", args);
|
|
342
|
+
// An article-bound run is a kernel job, polled by `kernel status` (get_kernel_run_status),
|
|
343
|
+
// not an endpoint run: the finished draft lands in the article, not here.
|
|
344
|
+
const kernelJobId = toolField(result, "kernel_job_id");
|
|
345
|
+
if (kernelJobId) {
|
|
346
|
+
ok(ctx, `Kernel run started into the article. Check progress with: kernel status ${kernelJobId}`);
|
|
347
|
+
printResult(io, flags, result);
|
|
348
|
+
return 0;
|
|
349
|
+
}
|
|
365
350
|
const runId = toolField(result, "run_id");
|
|
366
351
|
if (!runId) {
|
|
367
352
|
printResult(io, flags, result);
|
package/lib/commands/phantom.mjs
CHANGED
|
@@ -59,6 +59,7 @@ export const ARGS = {
|
|
|
59
59
|
customer_ref: { flag: "customer-ref" },
|
|
60
60
|
configure: { value: (flags) => (flags["no-configure"] === true ? false : undefined) },
|
|
61
61
|
config: { value: (flags) => readJsonObjectFlag(flags, "config") },
|
|
62
|
+
composition: { value: (flags) => readJsonObjectFlag(flags, "composition") },
|
|
62
63
|
client_domain: { flag: "client-domain" },
|
|
63
64
|
dry_run: { flag: "dry-run", type: "bool" },
|
|
64
65
|
},
|