@letterstory/cli 0.176.78 → 0.176.80

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
@@ -85,7 +85,7 @@ import {
85
85
  import { fetchParkedSections, withoutParked } from "./parked.mjs";
86
86
 
87
87
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
88
- export const VERSION = "0.176.78";
88
+ export const VERSION = "0.176.80";
89
89
 
90
90
  /** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
91
91
  export const EXIT_PAYMENT_REQUIRED = 3;
@@ -274,9 +274,9 @@ export const BOOLEAN_FLAGS = new Set([
274
274
  "resolve",
275
275
  "reopen",
276
276
  "skip",
277
- // `phantom-onboard domain` / `admin create-org --onboard` switches.
277
+ // `phantom-onboard domain` / `admin create-org --onboard` switches. (`--status` is a switch only on
278
+ // phantom-onboard, SWITCH_FLAGS_BY_COMMAND: everywhere else it takes a value, `--status parked`.)
278
279
  "watch",
279
- "status",
280
280
  "no-phantom",
281
281
  "no-visuals",
282
282
  "no-enhance",
@@ -424,6 +424,13 @@ export const BOOLEAN_FLAGS = new Set([
424
424
  */
425
425
  const VALUE_FLAGS_BY_COMMAND = { automations: new Set(["on"]) };
426
426
 
427
+ /**
428
+ * Flags that are switches on one command and take a value everywhere else. `--status` is "show me the job" on
429
+ * phantom-onboard (onboard.mjs), and a value on every other (`admin recipes save --status parked`, `admin crm
430
+ * prospect-orgs --status ready`): as a global switch, `--status parked` dropped "parked" (2026-11-09).
431
+ */
432
+ export const SWITCH_FLAGS_BY_COMMAND = { "phantom-onboard": new Set(["status"]), onboard: new Set(["status"]) };
433
+
427
434
  /**
428
435
  * @param {string[]} argv
429
436
  * @returns {{ positionals: string[], flags: Record<string, string | boolean | string[]> }}
@@ -432,6 +439,7 @@ export function parseArgs(argv) {
432
439
  const positionals = [];
433
440
  const flags = {};
434
441
  const valueFlags = VALUE_FLAGS_BY_COMMAND[argv[0]] ?? new Set();
442
+ const switchFlags = SWITCH_FLAGS_BY_COMMAND[argv[0]] ?? new Set();
435
443
  const setFlag = (name, value) => {
436
444
  if (Object.prototype.hasOwnProperty.call(flags, name)) {
437
445
  flags[name] = [].concat(flags[name], value);
@@ -452,7 +460,12 @@ export function parseArgs(argv) {
452
460
  }
453
461
  const name = tok.slice(2);
454
462
  const next = argv[i + 1];
455
- if ((BOOLEAN_FLAGS.has(name) && !valueFlags.has(name)) || next === undefined || next.startsWith("--")) {
463
+ if (
464
+ (BOOLEAN_FLAGS.has(name) && !valueFlags.has(name)) ||
465
+ switchFlags.has(name) ||
466
+ next === undefined ||
467
+ next.startsWith("--")
468
+ ) {
456
469
  flags[name] = true;
457
470
  } else {
458
471
  setFlag(name, next);
@@ -648,7 +661,7 @@ Reviewers:
648
661
  schedule]
649
662
  [--prompt <what Letterpress does with each event>] [--slack-channel <C…>] [--instruction <which events>]
650
663
  [--event <name>] [--kind post|landing] [--competitor <host>] [--site <host>]
651
- [--every <n> --unit hours|days|weeks|months] [--sandbox]
664
+ [--every <n> --unit hours|days|weeks|months] [--facts <a,b>] [--sandbox] [--recipe <id>]
652
665
  [--hot-leads-only] [--per-day <n>] [--backfill all|<YYYY-MM-DD>] [--off]
653
666
  Make one (a template fills what you leave out): it starts
654
667
  from now (--backfill also runs it on past events, oldest
@@ -656,7 +669,10 @@ Reviewers:
656
669
  to --slack-channel with its buttons. --trigger schedule
657
670
  --every 2 --unit weeks is a recurring one (on the calendar:
658
671
  Monday, the 1st); --sandbox always runs its prompt in a Build
659
- sandbox (off, Letterpress decides per event)
672
+ sandbox (off, Letterpress decides per event); --facts
673
+ names what each tick carries (merged_changes, page_reads,
674
+ new_pages_unlinked, striking_queries, losing_pages);
675
+ --recipe makes a Plan recipe's own
660
676
  automate set <automation-id> [--name <n>] [--instruction <text>] [--prompt <text>] [--slack-channel <C…>|none]
661
677
  [--sandbox|--no-sandbox] [--backfill all|<YYYY-MM-DD>] [--on|--off] ...
662
678
  automate try [<automation-id>] [--trigger <t> --prompt <text> --instruction <text> ...] [--limit <n>]
@@ -5134,6 +5134,10 @@ const RECIPE_FILE_FIELDS = [
5134
5134
  // The inputs the fit is told a recipe cannot run without (2026-11-08: left out here, an import never carried them).
5135
5135
  "requires",
5136
5136
  "runs",
5137
+ // The recurring automation a recipe carries (runs automation:recipe); left out here, an import never reached prod.
5138
+ "automation",
5139
+ // The build's declared tools and scoped writes (left out here, an export dropped them).
5140
+ "tool_access",
5137
5141
  "primitives_access",
5138
5142
  "immediate",
5139
5143
  "status",
@@ -5176,6 +5180,12 @@ function recipeDetail(r) {
5176
5180
  ` reads: ${r.reads?.length ? r.reads.join(", ") : "— (not written: every probe runs)"}`,
5177
5181
  ` status: ${r.status === "parked" ? `parked${r.needs ? `, needs ${r.needs}` : ""}` : "live"}`,
5178
5182
  ` runs: ${r.runs || "one change to the site's code, from its own directions"}`,
5183
+ ...(r.automation
5184
+ ? [
5185
+ ` automation: "${r.automation.name}" every ${r.automation.every} ${r.automation.unit}, carrying ${(r.automation.facts ?? []).join(", ") || "no facts"}`,
5186
+ ` its prompt: ${r.automation.prompt}`,
5187
+ ]
5188
+ : []),
5179
5189
  ...(r.primitives_access ? [" letter's tools: its build may use them (primitives_access)"] : []),
5180
5190
  ...(r.immediate ? [" immediate: a quick win: the Plan puts one in every top three"] : []),
5181
5191
  ...(variations.length > 1
@@ -46,6 +46,8 @@ const triggerParams = {
46
46
  // --trigger schedule --every 2 --unit weeks: a recurring automation, on the calendar (Monday, the 1st).
47
47
  every: { flag: "every", type: "num" },
48
48
  unit: { flag: "unit", enum: UNITS },
49
+ // --facts striking_queries,losing_pages: what each tick of a schedule carries, read by Letter before the turn.
50
+ facts: { flag: "facts", type: "list" },
49
51
  },
50
52
  };
51
53
  // --sandbox / --no-sandbox: always run the prompt in a Build sandbox (the repo and Letter's tools); off, Letterpress decides per event.
@@ -114,6 +116,8 @@ export const ARGS = {
114
116
  create_event_automation: {
115
117
  destination,
116
118
  template: { flag: "template", enum: TEMPLATES },
119
+ // --recipe <id>: make the automation a Plan recipe carries (the Plan row's own call).
120
+ recipe: { flag: "recipe" },
117
121
  name: { flag: "name" },
118
122
  trigger: { flag: "trigger", enum: TRIGGERS },
119
123
  trigger_params: triggerParams,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.176.78",
3
+ "version": "0.176.80",
4
4
  "description": "Spin up and manage Letter phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",