@letterstory/cli 0.33.5 → 0.33.7

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 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.33.5";
48
+ export const VERSION = "0.33.7";
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.
@@ -109,6 +109,7 @@ export const ARGS = {
109
109
  input: { value: (flags) => readBodyInput(flags) },
110
110
  kernel_id: "kernel",
111
111
  target_word_count: { flag: "words", type: "num" },
112
+ target_word_tolerance: { flag: "words-tolerance", type: "num" },
112
113
  label: "label",
113
114
  // The flag is --read-as, which is what shipped; an earlier draft called it --brief-mode.
114
115
  content_kind: {
@@ -198,6 +199,26 @@ export const ARGS = {
198
199
  endpoint_id: { positional: 1, label: "endpoint-id", required: true },
199
200
  config: { value: (flags) => readJsonFileFlag(flags, "file") },
200
201
  },
202
+ // The eval itself is one JSON file (--file), not flags — `detector` is a discriminated
203
+ // union with a different shape per kind, which flags-per-field cannot represent without
204
+ // nine different flag sets. Each field below reads the same file; a small re-parse per
205
+ // field, harmless for a one-shot CLI command against a small file.
206
+ add_kernel_custom_eval: {
207
+ kernel_id: { positional: 1, label: "kernel-id", required: true },
208
+ // `value` sources aren't checked against `required` (see shared.mjs readArgSource) —
209
+ // a missing id/name/detector reaches the tool call and comes back as the tool's own
210
+ // "Invalid arguments" error, same as any other malformed submission.
211
+ id: { value: (flags) => readJsonFileFlag(flags, "file")?.id },
212
+ name: { value: (flags) => readJsonFileFlag(flags, "file")?.name },
213
+ description: { value: (flags) => readJsonFileFlag(flags, "file")?.description },
214
+ detector: { value: (flags) => readJsonFileFlag(flags, "file")?.detector },
215
+ repair: { value: (flags) => readJsonFileFlag(flags, "file")?.repair },
216
+ regimes: { value: (flags) => readJsonFileFlag(flags, "file")?.regimes },
217
+ },
218
+ remove_kernel_custom_eval: {
219
+ kernel_id: { positional: 1, label: "kernel-id", required: true },
220
+ eval_id: { positional: 2, label: "eval-id", required: true },
221
+ },
201
222
  };
202
223
 
203
224
  export async function cmdKernel(ctx) {
@@ -215,6 +236,8 @@ export async function cmdKernel(ctx) {
215
236
  return kernelEndpoints(rest);
216
237
  case "endpoint":
217
238
  return kernelEndpoint(rest);
239
+ case "eval":
240
+ return kernelEval(rest);
218
241
  case "write":
219
242
  return kernelWrite(rest);
220
243
  case "polish":
@@ -227,7 +250,7 @@ export async function cmdKernel(ctx) {
227
250
  return kernelBalance(rest);
228
251
  default:
229
252
  throw new CliError(
230
- `Unknown kernel subcommand: ${sub ?? "(none)"}. Try: list, endpoints, endpoint, write, polish, run-status, runs, balance, run, status`
253
+ `Unknown kernel subcommand: ${sub ?? "(none)"}. Try: list, endpoints, endpoint, eval, write, polish, run-status, runs, balance, run, status`
231
254
  );
232
255
  }
233
256
  }
@@ -402,6 +425,54 @@ async function kernelEndpoint(ctx) {
402
425
  throw new CliError(`Unknown kernel endpoint action: ${action ?? "(none)"}. Try: create, delete, config`);
403
426
  }
404
427
 
428
+ /**
429
+ * `kernel eval add|rm` — an org-owned kernel's `rules.custom[]`, its own evals filed
430
+ * alongside the kernels service's built-in rules.
431
+ *
432
+ * `add` reads the whole eval (id/name/description/detector/repair/regimes) from one
433
+ * JSON file rather than flags: `detector` is a discriminated union with a different
434
+ * shape per kind, which a flag-per-field mapping (the pattern the rest of this file
435
+ * uses) cannot represent without nine different flag sets. Every genuinely new id
436
+ * lands at status "proposed" on the kernels service and is never auto-activated —
437
+ * this command cannot change that, only file the proposal.
438
+ */
439
+ async function kernelEval(ctx) {
440
+ const { client, positionals, flags, io } = ctx;
441
+ const action = positionals[0];
442
+ if (action === "add") {
443
+ if (flagStr(flags.file) === undefined) {
444
+ throw new CliError(
445
+ "Provide the eval as JSON with --file <path> (id/name/description/detector/repair/regimes)."
446
+ );
447
+ }
448
+ const args = argsFromFlags(ARGS.add_kernel_custom_eval, flags, positionals);
449
+ const result = await client.callTool("add_kernel_custom_eval", args);
450
+ const filing = toolField(result, "custom_evals");
451
+ if (filing?.filed?.includes(args.id)) ok(ctx, `Filed "${args.id}" as a proposal (status: proposed).`);
452
+ else if (filing?.skipped?.includes(args.id))
453
+ ok(
454
+ ctx,
455
+ `"${args.id}" was already filed from an earlier submission — this only updated the kernel's own declaration.`
456
+ );
457
+ printResult(io, flags, result);
458
+ return 0;
459
+ }
460
+ if (action === "rm" || action === "remove" || action === "delete") {
461
+ const args = argsFromFlags(ARGS.remove_kernel_custom_eval, flags, positionals);
462
+ if (!flags.yes) {
463
+ io.error(
464
+ `This only stops declaring the eval on this kernel — it does NOT retire anything already filed or approved server-side. Re-run with --yes to confirm: ${ctx.bin} kernel eval rm ${args.kernel_id} ${args.eval_id} --yes`
465
+ );
466
+ return 1;
467
+ }
468
+ const result = await client.callTool("remove_kernel_custom_eval", args);
469
+ ok(ctx, `Stopped declaring "${args.eval_id}" on this kernel.`);
470
+ printResult(io, flags, result);
471
+ return 0;
472
+ }
473
+ throw new CliError(`Unknown kernel eval action: ${action ?? "(none)"}. Try: add, rm`);
474
+ }
475
+
405
476
  /**
406
477
  * The OTHER door: run the same pipeline against a document you already have, instead of
407
478
  * writing a new one. Decomposed into a brief and GENERATED FRESH (content_kind: "article",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.33.5",
3
+ "version": "0.33.7",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",