@letterstory/cli 0.177.5 → 0.177.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 +3 -1
- package/lib/commands/build.mjs +3 -0
- package/lib/commands/site.mjs +31 -1
- package/lib/commands/vary.mjs +3 -0
- package/package.json +1 -1
package/lib/cli.mjs
CHANGED
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
import { fetchParkedSections, withoutParked } from "./parked.mjs";
|
|
88
88
|
|
|
89
89
|
// Matches cli/package.json; publish-cli.yml rewrites both to the published version.
|
|
90
|
-
export const VERSION = "0.177.
|
|
90
|
+
export const VERSION = "0.177.7";
|
|
91
91
|
|
|
92
92
|
/** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
|
|
93
93
|
export const EXIT_PAYMENT_REQUIRED = 3;
|
|
@@ -1881,6 +1881,8 @@ The Site (one model of your whole marketing site, keyed by host and path):
|
|
|
1881
1881
|
site highlight <domain> [--off] Highlight a competitor; its changes lead the top changes
|
|
1882
1882
|
site prospect <url> [--pages <n>] [--max-pages <n>] [--depth <n>]
|
|
1883
1883
|
Staff: any company's site, no account: what Fix would list, each PR
|
|
1884
|
+
site suggest <host> --idea <id> | --draft-id <id>... | --pattern <folder> | --item <id> --path <path>
|
|
1885
|
+
Open PR on a suggestion the Site stores, as one job
|
|
1884
1886
|
|
|
1885
1887
|
Repo changes (Claude Code edits your repo in a sandbox; the Letter GitHub App opens a PR):
|
|
1886
1888
|
repo repos [--gitlab [--search <text>] [--page n]] Repos the Letter GitHub App can reach (--gitlab: the GitLab
|
package/lib/commands/build.mjs
CHANGED
|
@@ -71,6 +71,8 @@ const ARGS = {
|
|
|
71
71
|
recipe: "recipe",
|
|
72
72
|
// Preserve the account-specific task selected by the Plan.
|
|
73
73
|
fit_run: "fit-run",
|
|
74
|
+
// --plan-action <id>: a Plan row's account action started as an Idea (blog:post, outbound:campaign, …).
|
|
75
|
+
action: "plan-action",
|
|
74
76
|
// --accepted-quote '<json>': the price the Ideas row showed, echoed to accept what it buys.
|
|
75
77
|
accepted_quote: {
|
|
76
78
|
value: (flags) => {
|
|
@@ -256,6 +258,7 @@ async function buildStart(ctx) {
|
|
|
256
258
|
"subject",
|
|
257
259
|
"recipe",
|
|
258
260
|
"fit-run",
|
|
261
|
+
"plan-action",
|
|
259
262
|
"accepted-quote",
|
|
260
263
|
"action",
|
|
261
264
|
"notify-slack",
|
package/lib/commands/site.mjs
CHANGED
|
@@ -15,12 +15,14 @@
|
|
|
15
15
|
// site competitors → list_competitor_sites site watch-competitors [d] → watch_competitor_sites
|
|
16
16
|
// site highlight <domain> [--off] → set_competitor_highlight
|
|
17
17
|
// site prospect <url> → read_prospect_site (staff: any company's site, no account, nothing stored)
|
|
18
|
+
// site suggest <host> --idea <id> | --draft-id <id>… | --pattern <folder> | --item <id> --path <p> → start_suggestion
|
|
18
19
|
|
|
19
20
|
import { writeFileSync } from "node:fs";
|
|
20
21
|
|
|
21
22
|
import { CliError } from "../client.mjs";
|
|
22
23
|
import {
|
|
23
24
|
argsFromFlags,
|
|
25
|
+
flagCsv,
|
|
24
26
|
flagList,
|
|
25
27
|
flagNum,
|
|
26
28
|
flagStr,
|
|
@@ -193,6 +195,14 @@ const ARGS = {
|
|
|
193
195
|
decision: { flag: "decision", required: true, enum: ["accept", "dismiss"] },
|
|
194
196
|
reason: "reason",
|
|
195
197
|
},
|
|
198
|
+
start_suggestion: {
|
|
199
|
+
domain: { positional: 0, required: true, label: "host" },
|
|
200
|
+
idea_id: "idea",
|
|
201
|
+
draft_ids: { value: (flags) => (flagCsv(flags["draft-id"]).length ? flagCsv(flags["draft-id"]) : undefined) },
|
|
202
|
+
pattern_folder: "pattern",
|
|
203
|
+
observation_id: "item",
|
|
204
|
+
path: "path",
|
|
205
|
+
},
|
|
196
206
|
fix_site_observations: {
|
|
197
207
|
host: { positional: 0, required: true, label: "host" },
|
|
198
208
|
// Every positional after the host, plus --observation <id> (repeatable).
|
|
@@ -264,9 +274,11 @@ export async function cmdSite(ctx) {
|
|
|
264
274
|
return siteHighlight(rest);
|
|
265
275
|
case "prospect":
|
|
266
276
|
return siteProspect(rest);
|
|
277
|
+
case "suggest":
|
|
278
|
+
return siteSuggest(rest);
|
|
267
279
|
default:
|
|
268
280
|
throw new CliError(
|
|
269
|
-
`Unknown site subcommand: ${sub ?? "(none)"}. Try: list, map, refresh, unmap, tree, builds, metrics, page, observations, observe, dismiss, families, decide-family, proposals, propose, decide, fix, competitors, watch-competitors, highlight, prospect`
|
|
281
|
+
`Unknown site subcommand: ${sub ?? "(none)"}. Try: list, map, refresh, unmap, tree, builds, metrics, page, observations, observe, dismiss, families, decide-family, proposals, propose, decide, fix, competitors, watch-competitors, highlight, prospect, suggest`
|
|
270
282
|
);
|
|
271
283
|
}
|
|
272
284
|
}
|
|
@@ -396,6 +408,24 @@ async function siteMap(ctx) {
|
|
|
396
408
|
return 0;
|
|
397
409
|
}
|
|
398
410
|
|
|
411
|
+
/** A suggestion the Site stores, started as the Site's Open PR does: one job, its words read from what Letter stores. */
|
|
412
|
+
async function siteSuggest(ctx) {
|
|
413
|
+
const { client, flags, io } = ctx;
|
|
414
|
+
refuseUnknownFlags(ctx, ARGS.start_suggestion, ["idea", "draft-id", "pattern", "item", "path"]);
|
|
415
|
+
const args = argsFromFlags(ARGS.start_suggestion, flags, ctx.positionals);
|
|
416
|
+
const named = [args.idea_id, args.draft_ids, args.pattern_folder, args.observation_id].filter(Boolean).length;
|
|
417
|
+
if (named !== 1 || (args.observation_id && !args.path))
|
|
418
|
+
throw new CliError(
|
|
419
|
+
"Name one suggestion: site suggest <host> --idea <id> | --draft-id <id>… | --pattern <folder> | --item <id> --path <path>"
|
|
420
|
+
);
|
|
421
|
+
const result = await client.callTool("start_suggestion", args);
|
|
422
|
+
printResult(io, flags, result, (r) => {
|
|
423
|
+
if (r.status !== "started") return r.message ?? r.status;
|
|
424
|
+
return `Started: ${r.build.title} (${r.build.id})`;
|
|
425
|
+
});
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
|
|
399
429
|
/** Any company's site read as the Site and Fix read a customer's: what Fix would list, and each pull request. */
|
|
400
430
|
async function siteProspect(ctx) {
|
|
401
431
|
const { client, flags, io } = ctx;
|
package/lib/commands/vary.mjs
CHANGED
|
@@ -78,6 +78,9 @@ export const ARGS = {
|
|
|
78
78
|
},
|
|
79
79
|
launch_variational_test: {
|
|
80
80
|
brief: "brief",
|
|
81
|
+
// --block "<its words>" --after "<the challenger's>": test exactly these, with no model choosing.
|
|
82
|
+
block: "block",
|
|
83
|
+
after: "after",
|
|
81
84
|
page_url: "page",
|
|
82
85
|
site_id: "site",
|
|
83
86
|
name: "name",
|