@letterstory/cli 0.176.40 → 0.176.42

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
@@ -83,7 +83,7 @@ import {
83
83
  import { fetchParkedSections, withoutParked } from "./parked.mjs";
84
84
 
85
85
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
86
- export const VERSION = "0.176.40";
86
+ export const VERSION = "0.176.42";
87
87
 
88
88
  /** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
89
89
  export const EXIT_PAYMENT_REQUIRED = 3;
@@ -94,6 +94,8 @@ export const EXIT_PAYMENT_REQUIRED = 3;
94
94
  export const BOOLEAN_FLAGS = new Set([
95
95
  // build list: also move the builds' open changes along while polling.
96
96
  "advance",
97
+ // build list: only what the Plan started.
98
+ "from-plan",
97
99
  // build: a website or app of its own (deploy create's path). deploy create: hold until its build starts.
98
100
  "new-site",
99
101
  "wait",
@@ -625,16 +627,17 @@ Reviewers:
625
627
  automate list Your automations: an event, which ones it acts on,
626
628
  and what Letterpress then does
627
629
  automate show <automation-id>
628
- automate add [--template post_new_issues|recommended_actions|competitor_pages|icp_visitors|plan_updates]
630
+ automate add [--template post_new_issues|recommended_actions|competitor_pages|icp_visitors|vc_visitors|plan_updates]
629
631
  [--name <n>] [--trigger competitor_page|visitor_identified|issue_found|build_suggestion|plan_update|custom]
630
632
  [--prompt <what Letterpress does with each event>] [--slack-channel <C…>] [--instruction <which events>]
631
633
  [--event <name>] [--kind post|landing] [--competitor <host>] [--site <host>]
632
- [--hot-leads-only] [--per-day <n>] [--off]
634
+ [--hot-leads-only] [--per-day <n>] [--backfill all|<YYYY-MM-DD>] [--off]
633
635
  Make one (a template fills what you leave out): it starts
634
- from now, acts on its own, and posts each event it acts on
636
+ from now (--backfill also runs it on past events, oldest
637
+ first), acts on its own, and posts each event it acts on
635
638
  to --slack-channel with its buttons
636
639
  automate set <automation-id> [--name <n>] [--instruction <text>] [--prompt <text>] [--slack-channel <C…>|none]
637
- [--on|--off] ...
640
+ [--backfill all|<YYYY-MM-DD>] [--on|--off] ...
638
641
  automate try [<automation-id>] [--trigger <t> --prompt <text> --instruction <text> ...] [--limit <n>]
639
642
  What it would do with the latest events (acts on none)
640
643
  automate runs [--automation <id>] [--status acting|acted|skipped|failed|proposed|rejected] [--limit <n>]
@@ -1677,6 +1680,8 @@ Insights:
1677
1680
  them (--goal: one goal's strategies, else any); each pick waits --veto-hours for a veto. Settings shown when none given.
1678
1681
  plan pending [--site host] What Auto-Plan picked and is waiting to build
1679
1682
  plan veto <proposal-id> Veto one: it is never built
1683
+ plan start <proposal-id> Start one now (a Needs you pick, or one waiting out its review window)
1684
+ plan preview [--site host] What Auto-Plan would do first, before it is on
1680
1685
  plan later <action-id> [--outcome geo|…] [--site host] Queue a Plan row for later: Auto-Plan starts it once it's ready
1681
1686
  plan later remove <queued-id> Take a queued row back off
1682
1687
  plan strategies [--site host] [--archived] The goals typed on the Plan, each a strategy
@@ -1725,7 +1730,7 @@ Build (a change to your site, or launching what isn't code; the Build box's own
1725
1730
  Staff only. The same prompt on Letterpress-1 (as Build runs it) and on
1726
1731
  stock Claude Code and stock Codex, each a preview to compare
1727
1732
  build benchmarks [--id <uuid>] [--limit <n>] Staff only. Benchmarks, each arm's state, preview, cost and agent time
1728
- build list [--limit <n>] [--site <host>] [--kind build|fix] [--open|--archived]
1733
+ build list [--limit <n>] [--site <host>] [--kind build|fix] [--open|--archived] [--from-plan]
1729
1734
  Your builds, newest first, with where each stands
1730
1735
  build status <build-id> One build: each change's state, its preview and pull request
1731
1736
  build follow <build-id> [--json] What its agents do, line by line, until nothing in it is at
@@ -8,7 +8,14 @@ import { CliError } from "../client.mjs";
8
8
  import { printResult, ok, argsFromFlags, flagList, refuseUnknownFlags } from "./shared.mjs";
9
9
 
10
10
  const TRIGGERS = ["competitor_page", "visitor_identified", "issue_found", "build_suggestion", "plan_update", "custom"];
11
- const TEMPLATES = ["post_new_issues", "recommended_actions", "competitor_pages", "icp_visitors", "plan_updates"];
11
+ const TEMPLATES = [
12
+ "post_new_issues",
13
+ "recommended_actions",
14
+ "competitor_pages",
15
+ "icp_visitors",
16
+ "vc_visitors",
17
+ "plan_updates",
18
+ ];
12
19
  const STATUSES = ["pending", "proposed", "acting", "acted", "skipped", "failed", "rejected"];
13
20
 
14
21
  const triggerParams = {
@@ -31,6 +38,19 @@ const slackChannel = {
31
38
  : String(flags["slack-channel"]),
32
39
  };
33
40
  const enabled = { value: (flags) => (flags.off === true ? false : flags.on === true ? true : undefined) };
41
+ // --backfill all (the whole history the trigger's source keeps) or --backfill 2026-09-01 (from that day):
42
+ // also run it on past events, oldest first.
43
+ const backfill = {
44
+ value: (flags) => {
45
+ const v = flags.backfill;
46
+ if (v === undefined) return undefined;
47
+ if (v === true || v === "all") return "all";
48
+ const day = String(v);
49
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(day))
50
+ throw new CliError(`--backfill takes all or a day (YYYY-MM-DD), got: ${day}`);
51
+ return { since: `${day}T00:00:00Z` };
52
+ },
53
+ };
34
54
 
35
55
  /** --fact plan=team --fact seats=40 → { plan: "team", seats: 40 } (numbers and true/false read as such). */
36
56
  function factsOf(flags) {
@@ -69,6 +89,7 @@ export const ARGS = {
69
89
  prompt: { flag: "prompt" },
70
90
  slack_channel: slackChannel,
71
91
  enabled,
92
+ backfill,
72
93
  },
73
94
  update_event_automation: {
74
95
  automation_id: { positional: 0, label: "automation-id", required: true },
@@ -78,6 +99,7 @@ export const ARGS = {
78
99
  prompt: { flag: "prompt" },
79
100
  slack_channel: slackChannel,
80
101
  enabled,
102
+ backfill,
81
103
  },
82
104
  delete_event_automation: {
83
105
  automation_id: { positional: 0, label: "automation-id", required: true },
@@ -8,7 +8,7 @@
8
8
  // build benchmark <words…> → start_build_benchmark (staff only: Letterpress-1, stock Claude Code
9
9
  // and stock Codex on the same prompt, each a preview)
10
10
  // build benchmarks → list_build_benchmarks (staff only; --id <uuid> for one)
11
- // build list → list_growth_builds (newest first; --site, --kind, --open/--archived)
11
+ // build list → list_growth_builds (newest first; --site, --kind, --open/--archived, --from-plan)
12
12
  // build status <id> → list_growth_builds (one build: its steps, previews and PRs)
13
13
  // build follow <id> → list_growth_builds (advance) + get_repo_change_activity, until nothing is at work
14
14
  // build conversations → list_build_conversations
@@ -101,6 +101,8 @@ const ARGS = {
101
101
  archived: { flag: "archived", type: "bool", negate: "open" },
102
102
  // --advance: also move the builds' open changes along while polling (a queued change takes its sandbox, a merge asked for its next step).
103
103
  advance: { flag: "advance", type: "bool" },
104
+ // --from-plan: only what the Plan started (a strategy's row, Auto-Plan's pick), as the Plan's Actions list shows it.
105
+ from_plan: { flag: "from-plan", type: "bool" },
104
106
  },
105
107
  list_build_conversations: { limit: { flag: "limit", type: "num" } },
106
108
  get_build_conversation: {
@@ -272,7 +274,7 @@ async function readBuild(client, args) {
272
274
  /** `build list`: the organization's builds, newest first. */
273
275
  async function buildList(ctx) {
274
276
  const { client, flags, io } = ctx;
275
- refuseUnknownFlags(ctx, {}, ["limit", "kind", "site", "archived", "open", "advance"]);
277
+ refuseUnknownFlags(ctx, {}, ["limit", "kind", "site", "archived", "open", "advance", "from-plan"]);
276
278
  const args = argsFromFlags(ARGS.list_growth_builds, flags, []);
277
279
  const result = await client.callTool("list_growth_builds", args);
278
280
  printResult(io, flags, result, (r) =>
@@ -6,6 +6,8 @@
6
6
  // [--slack-channel <C…>|none] → set_auto_plan
7
7
  // plan pending → list_auto_plan_proposals (status pending)
8
8
  // plan veto <proposal-id> → veto_auto_plan_proposal
9
+ // plan start <proposal-id> → start_auto_plan_proposal (a Needs you pick, or one waiting out its review window)
10
+ // plan preview → preview_auto_plan (what Auto-Plan would do first)
9
11
  // plan later <action-id> [--outcome geo|…] → queue_plan_action (Auto-Plan starts it once it's ready)
10
12
  // plan later remove <queued-id> → unqueue_plan_action
11
13
  // plan strategies [--archived] → list_plan_strategies (the goals typed on the Plan)
@@ -78,6 +80,8 @@ export const ARGS = {
78
80
  },
79
81
  unqueue_plan_action: { id: { positional: 0, required: true, label: "queued-id" } },
80
82
  veto_auto_plan_proposal: { id: { positional: 0, required: true, label: "proposal-id" } },
83
+ start_auto_plan_proposal: { id: { positional: 0, required: true, label: "proposal-id" } },
84
+ preview_auto_plan: { domain: "site" },
81
85
  list_plan_strategies: { domain: "site", archived: { flag: "archived", type: "bool" } },
82
86
  create_plan_strategy: {
83
87
  domain: "site",
@@ -143,6 +147,25 @@ export async function cmdPlan(ctx) {
143
147
  );
144
148
  return 0;
145
149
  }
150
+ if (sub === "start") {
151
+ refuseUnknownFlags(ctx, {}, []);
152
+ const result = await client.callTool(
153
+ "start_auto_plan_proposal",
154
+ argsFromFlags(ARGS.start_auto_plan_proposal, flags, rest)
155
+ );
156
+ printResult(io, flags, result, (r) => r.message);
157
+ return 0;
158
+ }
159
+ if (sub === "preview") {
160
+ refuseUnknownFlags(ctx, {}, ["site"]);
161
+ const result = await client.callTool("preview_auto_plan", argsFromFlags(ARGS.preview_auto_plan, flags, rest));
162
+ printResult(io, flags, result, (r) =>
163
+ [r.message, ...r.picks.map((p) => ` ${p.kind === "pr" ? "opens a PR " : "needs you "} ${p.title}`)].join(
164
+ "\n"
165
+ )
166
+ );
167
+ return 0;
168
+ }
146
169
  if (sub === "veto") {
147
170
  refuseUnknownFlags(ctx, {}, []);
148
171
  const result = await client.callTool(
@@ -187,6 +210,6 @@ export async function cmdPlan(ctx) {
187
210
  throw new CliError('Usage: plan strategy add "<words…>" | plan strategy archive <strategy-id> [--restore]');
188
211
  }
189
212
  throw new CliError(
190
- "Usage: plan auto [settings…] | plan pending | plan veto <proposal-id> | plan later <action-id> | plan later remove <id> | plan strategies | plan strategy add|archive"
213
+ "Usage: plan auto [settings…] | plan pending | plan veto <proposal-id> | plan start <proposal-id> | plan preview | plan later <action-id> | plan later remove <id> | plan strategies | plan strategy add|archive"
191
214
  );
192
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.176.40",
3
+ "version": "0.176.42",
4
4
  "description": "Spin up and manage Letter phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",