@letterstory/cli 0.176.52 → 0.176.54
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 +21 -9
- package/lib/commands/ask.mjs +4 -2
- package/lib/commands/automate.mjs +23 -1
- package/lib/commands/build.mjs +2 -0
- package/lib/commands/plan.mjs +16 -8
- package/package.json +1 -1
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.
|
|
88
|
+
export const VERSION = "0.176.54";
|
|
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;
|
|
@@ -117,10 +117,12 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
117
117
|
"keep-key",
|
|
118
118
|
"delete-key",
|
|
119
119
|
"keep",
|
|
120
|
-
// automate add/set: on or off; only identified visitors marked hot leads.
|
|
120
|
+
// automate add/set: on or off; only identified visitors marked hot leads; run the prompt in a Build sandbox.
|
|
121
121
|
"on",
|
|
122
122
|
"off",
|
|
123
123
|
"hot-leads-only",
|
|
124
|
+
"sandbox",
|
|
125
|
+
"no-sandbox",
|
|
124
126
|
// admin crm prospect-org: start (or retry) the org prepared for the booked call.
|
|
125
127
|
"start",
|
|
126
128
|
// site research-builds: run now even when the stored pass is under an hour old.
|
|
@@ -136,6 +138,8 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
136
138
|
// build: repeat an open build's ask; post its progress in the org's Slack channel.
|
|
137
139
|
"again",
|
|
138
140
|
"plan-only",
|
|
141
|
+
// build: every change reads Letter's tools from its sandbox.
|
|
142
|
+
"primitives-access",
|
|
139
143
|
// build list: only Build's Archived tab (--open, already listed, is its Open tab).
|
|
140
144
|
"archived",
|
|
141
145
|
// plan pending --queued: only the rows a person queued for later.
|
|
@@ -198,6 +202,8 @@ export const BOOLEAN_FLAGS = new Set([
|
|
|
198
202
|
"no-control",
|
|
199
203
|
"own-beat",
|
|
200
204
|
"refresh",
|
|
205
|
+
// ask --more: every row that fits, not only the top ones.
|
|
206
|
+
"more",
|
|
201
207
|
"preview",
|
|
202
208
|
"with-preview",
|
|
203
209
|
// repo …: the repo is a GitLab project (--repo group/subgroup/project).
|
|
@@ -633,17 +639,22 @@ Reviewers:
|
|
|
633
639
|
automate list Your automations: an event, which ones it acts on,
|
|
634
640
|
and what Letterpress then does
|
|
635
641
|
automate show <automation-id>
|
|
636
|
-
automate add [--template post_new_issues|recommended_actions|competitor_pages|
|
|
637
|
-
|
|
642
|
+
automate add [--template post_new_issues|fix_new_issues|recommended_actions|competitor_pages|competitor_takes|
|
|
643
|
+
icp_visitors|vc_visitors|plan_updates|weekly_release_notes|monthly_page_refresh]
|
|
644
|
+
[--name <n>] [--trigger competitor_page|visitor_identified|issue_found|build_suggestion|plan_update|custom|schedule]
|
|
638
645
|
[--prompt <what Letterpress does with each event>] [--slack-channel <C…>] [--instruction <which events>]
|
|
639
646
|
[--event <name>] [--kind post|landing] [--competitor <host>] [--site <host>]
|
|
647
|
+
[--every <n> --unit hours|days|weeks|months] [--sandbox]
|
|
640
648
|
[--hot-leads-only] [--per-day <n>] [--backfill all|<YYYY-MM-DD>] [--off]
|
|
641
649
|
Make one (a template fills what you leave out): it starts
|
|
642
650
|
from now (--backfill also runs it on past events, oldest
|
|
643
651
|
first), acts on its own, and posts each event it acts on
|
|
644
|
-
to --slack-channel with its buttons
|
|
652
|
+
to --slack-channel with its buttons. --trigger schedule
|
|
653
|
+
--every 2 --unit weeks is a recurring one (on the calendar:
|
|
654
|
+
Monday, the 1st); --sandbox always runs its prompt in a Build
|
|
655
|
+
sandbox (off, Letterpress decides per event)
|
|
645
656
|
automate set <automation-id> [--name <n>] [--instruction <text>] [--prompt <text>] [--slack-channel <C…>|none]
|
|
646
|
-
[--backfill all|<YYYY-MM-DD>] [--on|--off] ...
|
|
657
|
+
[--sandbox|--no-sandbox] [--backfill all|<YYYY-MM-DD>] [--on|--off] ...
|
|
647
658
|
automate try [<automation-id>] [--trigger <t> --prompt <text> --instruction <text> ...] [--limit <n>]
|
|
648
659
|
What it would do with the latest events (acts on none)
|
|
649
660
|
automate runs [--automation <id>] [--status acting|acted|skipped|failed|proposed|rejected] [--limit <n>]
|
|
@@ -1678,17 +1689,17 @@ Mail:
|
|
|
1678
1689
|
(any phone format; country as a name or a 2-letter code)
|
|
1679
1690
|
|
|
1680
1691
|
Insights:
|
|
1681
|
-
ask [<words…>] [--outcome geo|seo|…] [--lens fix|build] [--site host]
|
|
1692
|
+
ask [<words…>] [--outcome geo|seo|…] [--more] [--lens fix|build] [--site host]
|
|
1682
1693
|
Ask Letterpress what to do next: the plan for an outcome (the
|
|
1683
1694
|
Plan tab's box), what's broken (--lens fix, most pressing
|
|
1684
1695
|
first), what to build (--lens build), or your own words. Nothing asked:
|
|
1685
1696
|
each list's head. The same answer as the console and Slack.
|
|
1686
1697
|
plan auto [activate|disable] [--site host] [--veto-hours <1-168>|off] [--pace-hours <1-168>]
|
|
1687
1698
|
[--delivery build|build_pr|build_merge]
|
|
1688
|
-
[--aggression low|medium|high|xhigh] [--
|
|
1699
|
+
[--aggression low|medium|high|xhigh] [--strategies geo,seo,agent_conviction,inbound_conversion|any]
|
|
1689
1700
|
[--slack-channel <C…>|none]
|
|
1690
1701
|
Auto-Plan on a site: Letterpress picks its strategies and builds
|
|
1691
|
-
them
|
|
1702
|
+
them under the site's strategies (--strategies, any by default; the Plan reads the same set); each pick waits --veto-hours for a veto. Settings shown when none given.
|
|
1692
1703
|
plan pending [--site host] What Auto-Plan picked and is waiting to build
|
|
1693
1704
|
plan veto <proposal-id> Veto one: it is never built
|
|
1694
1705
|
plan start <proposal-id> Start one now (a Needs you pick, or one waiting out its review window)
|
|
@@ -1726,6 +1737,7 @@ Build (a change to your site, or launching what isn't code; the Build box's own
|
|
|
1726
1737
|
build <words…> [--prompt <text>] [--site <host>] [--subject <host/path>]... [--action build|build_pr|build_merge|slack|linear]
|
|
1727
1738
|
[--attach <path>]... [--attach-url <name>=<https url>]... [--attach-ref <path>]... [--attach-url-ref <name>=<https url>]...
|
|
1728
1739
|
[--harness letterpress-1|claude-code|codex] [--effort low|medium|high|xhigh] [--notify-slack] [--again] [--new-site]
|
|
1740
|
+
[--primitives-access]
|
|
1729
1741
|
Build from your words: "add a pricing page" opens a preview or PR;
|
|
1730
1742
|
"launch a phantom for us", "set up mailers" or "onboard my blog" is
|
|
1731
1743
|
done by Build itself (a phantom site buys its own domain), and the
|
package/lib/commands/ask.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// `ask` — ask Letterpress, the one door (docs/architecture/one-recipe-engine.md §9b): what should
|
|
2
2
|
// this account do next. The same answer as the console's Plan, Build and Fix tabs and Slack.
|
|
3
3
|
// ask → each list's head: what's broken, what to build
|
|
4
|
-
// ask --outcome geo|seo|… → the plan for that outcome (
|
|
4
|
+
// ask --outcome geo|seo|… → the plan for that outcome (Ideas filtered to it); --more: every row that fits
|
|
5
5
|
// ask --strategy <id> → a typed strategy's next actions (plan strategies)
|
|
6
6
|
// ask --lens fix | --lens build → what's broken (most pressing first) | what to build
|
|
7
7
|
// ask "<words…>" → in your own words; what nothing does comes back as unmet
|
|
@@ -21,13 +21,15 @@ export const ARGS = {
|
|
|
21
21
|
found: "found",
|
|
22
22
|
// --refresh: decide every strategy again from the facts as they are now (the standing fit is read otherwise).
|
|
23
23
|
refresh: { flag: "refresh", type: "bool" },
|
|
24
|
+
// --more: every row that fits, not only the top ones (the Ideas list's Show all).
|
|
25
|
+
more: { flag: "more", type: "bool" },
|
|
24
26
|
domain: "site",
|
|
25
27
|
},
|
|
26
28
|
};
|
|
27
29
|
|
|
28
30
|
export async function cmdAsk(ctx) {
|
|
29
31
|
const { client, flags, io } = ctx;
|
|
30
|
-
refuseUnknownFlags(ctx, {}, ["outcome", "strategy", "lens", "words", "found", "site", "refresh"]);
|
|
32
|
+
refuseUnknownFlags(ctx, {}, ["outcome", "strategy", "lens", "words", "found", "site", "refresh", "more"]);
|
|
31
33
|
const args = argsFromFlags(ARGS.ask_letterpress, flags, ctx.positionals, {});
|
|
32
34
|
if ([args.outcome, args.strategy_id, args.lens, args.words].filter(Boolean).length > 1)
|
|
33
35
|
throw new CliError("One ask at a time: --outcome, --strategy <id>, --lens fix|build, or your words.");
|
|
@@ -7,15 +7,28 @@
|
|
|
7
7
|
import { CliError } from "../client.mjs";
|
|
8
8
|
import { printResult, ok, argsFromFlags, flagList, flagStr, refuseUnknownFlags } from "./shared.mjs";
|
|
9
9
|
|
|
10
|
-
const TRIGGERS = [
|
|
10
|
+
const TRIGGERS = [
|
|
11
|
+
"competitor_page",
|
|
12
|
+
"visitor_identified",
|
|
13
|
+
"issue_found",
|
|
14
|
+
"build_suggestion",
|
|
15
|
+
"plan_update",
|
|
16
|
+
"custom",
|
|
17
|
+
"schedule",
|
|
18
|
+
];
|
|
11
19
|
const TEMPLATES = [
|
|
12
20
|
"post_new_issues",
|
|
21
|
+
"fix_new_issues",
|
|
13
22
|
"recommended_actions",
|
|
14
23
|
"competitor_pages",
|
|
24
|
+
"competitor_takes",
|
|
15
25
|
"icp_visitors",
|
|
16
26
|
"vc_visitors",
|
|
17
27
|
"plan_updates",
|
|
28
|
+
"weekly_release_notes",
|
|
29
|
+
"monthly_page_refresh",
|
|
18
30
|
];
|
|
31
|
+
const UNITS = ["hours", "days", "weeks", "months"];
|
|
19
32
|
const STATUSES = ["pending", "proposed", "acting", "acted", "skipped", "failed", "rejected"];
|
|
20
33
|
|
|
21
34
|
const triggerParams = {
|
|
@@ -26,8 +39,15 @@ const triggerParams = {
|
|
|
26
39
|
hot_leads_only: { flag: "hot-leads-only", type: "bool" },
|
|
27
40
|
event: { flag: "event" },
|
|
28
41
|
per_day: { flag: "per-day", type: "num" },
|
|
42
|
+
// --trigger schedule --every 2 --unit weeks: a recurring automation, on the calendar (Monday, the 1st).
|
|
43
|
+
every: { flag: "every", type: "num" },
|
|
44
|
+
unit: { flag: "unit", enum: UNITS },
|
|
29
45
|
},
|
|
30
46
|
};
|
|
47
|
+
// --sandbox / --no-sandbox: always run the prompt in a Build sandbox (the repo and Letter's tools); off, Letterpress decides per event.
|
|
48
|
+
const sandbox = {
|
|
49
|
+
value: (flags) => (flags["no-sandbox"] === true ? false : flags.sandbox === true ? true : undefined),
|
|
50
|
+
};
|
|
31
51
|
// --slack-channel C0123ABCD (repo slack-targets), or none to post nothing.
|
|
32
52
|
const slackChannel = {
|
|
33
53
|
value: (flags) =>
|
|
@@ -96,6 +116,7 @@ export const ARGS = {
|
|
|
96
116
|
instruction: { flag: "instruction" },
|
|
97
117
|
prompt: { flag: "prompt" },
|
|
98
118
|
slack_channel: slackChannel,
|
|
119
|
+
sandbox,
|
|
99
120
|
enabled,
|
|
100
121
|
backfill,
|
|
101
122
|
},
|
|
@@ -108,6 +129,7 @@ export const ARGS = {
|
|
|
108
129
|
instruction: { flag: "instruction" },
|
|
109
130
|
prompt: { flag: "prompt" },
|
|
110
131
|
slack_channel: slackChannel,
|
|
132
|
+
sandbox,
|
|
111
133
|
enabled,
|
|
112
134
|
backfill,
|
|
113
135
|
},
|
package/lib/commands/build.mjs
CHANGED
|
@@ -50,6 +50,8 @@ const ARGS = {
|
|
|
50
50
|
files: { value: (_flags, _positionals, extra) => (extra.files?.length ? extra.files : undefined) },
|
|
51
51
|
delivery: { flag: "action", enum: ["build", "build_pr", "build_merge", "slack", "linear"] },
|
|
52
52
|
notify_slack: { flag: "notify-slack", type: "bool" },
|
|
53
|
+
// --primitives-access: every change reads Letter's tools from its sandbox (a read-only MCP key beside the repo).
|
|
54
|
+
primitives_access: { flag: "primitives-access", type: "bool" },
|
|
53
55
|
harness: { flag: "harness", enum: ["letterpress-1", "claude-code", "codex"] },
|
|
54
56
|
// --branch <name>: where its changes start and its pull requests go; omitted, the branch that builds the site.
|
|
55
57
|
base_branch: "branch",
|
package/lib/commands/plan.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// organization's own domain). The same calls as the Plan's modal and its sidebar's Pending rows.
|
|
3
3
|
// plan auto → get_auto_plan
|
|
4
4
|
// plan auto [activate|disable] [--veto-hours <1-168>|off] [--pace-hours <1-168>] [--delivery build|build_pr|build_merge]
|
|
5
|
-
// [--aggression low|medium|high|xhigh] [--
|
|
5
|
+
// [--aggression low|medium|high|xhigh] [--strategies geo,seo|any]
|
|
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
|
|
@@ -67,15 +67,23 @@ export const ARGS = {
|
|
|
67
67
|
// How far each pick goes: a preview, a pull request, or one merged once ready.
|
|
68
68
|
delivery: { flag: "delivery", enum: ["build", "build_pr", "build_merge"] },
|
|
69
69
|
aggression: { flag: "aggression", enum: ["low", "medium", "high", "xhigh"] },
|
|
70
|
-
// --
|
|
71
|
-
|
|
70
|
+
// --strategies geo,seo: the site's strategies (what the Plan reads under, what Auto-Plan picks from), replaced
|
|
71
|
+
// whole; --strategies any (or none) reads every strategy.
|
|
72
|
+
strategies: {
|
|
72
73
|
value: (flags) => {
|
|
73
|
-
const v = flagStr(flags.
|
|
74
|
+
const v = flagStr(flags.strategies);
|
|
74
75
|
if (v === undefined) return undefined;
|
|
75
|
-
if (v === "any") return
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
if (v === "any" || v === "") return [];
|
|
77
|
+
const list = v
|
|
78
|
+
.split(",")
|
|
79
|
+
.map((x) => x.trim())
|
|
80
|
+
.filter(Boolean);
|
|
81
|
+
for (const g of list)
|
|
82
|
+
if (!["agent_conviction", "geo", "seo", "inbound_conversion"].includes(g))
|
|
83
|
+
throw new CliError(
|
|
84
|
+
"--strategies takes agent_conviction, geo, seo, inbound_conversion (comma-separated), or any."
|
|
85
|
+
);
|
|
86
|
+
return list;
|
|
79
87
|
},
|
|
80
88
|
},
|
|
81
89
|
slack_channel: {
|