@letterstory/cli 0.69.0 → 0.70.1
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/README.md +1 -0
- package/lib/cli.mjs +6 -3
- package/lib/commands/admin.mjs +14 -2
- package/lib/commands/collection.mjs +14 -1
- package/lib/commands/outbound.mjs +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -161,6 +161,7 @@ publishing, targets, measurement) that produces and publishes posts on a cadence
|
|
|
161
161
|
|
|
162
162
|
```bash
|
|
163
163
|
letterstory collection list # public_id = the HTTP door's address
|
|
164
|
+
letterstory collection overview # site, state, posts, in Google, AI reads per collection
|
|
164
165
|
letterstory collection new --name "Launches" --config-file cfg.json
|
|
165
166
|
letterstory collection config <id> # print the one file
|
|
166
167
|
letterstory collection config <id> --config '{"targets":{"enabled":true,"tier":"ramping"}}' # patch it
|
package/lib/cli.mjs
CHANGED
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
} from "./commands.mjs";
|
|
57
57
|
|
|
58
58
|
// Keep in sync with cli/package.json.
|
|
59
|
-
export const VERSION = "0.
|
|
59
|
+
export const VERSION = "0.70.1";
|
|
60
60
|
|
|
61
61
|
// Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
|
|
62
62
|
// can't accidentally swallow the id as --json's value.
|
|
@@ -201,6 +201,7 @@ Auth:
|
|
|
201
201
|
|
|
202
202
|
Collections (the content engine as a primitive — one door, 'collection run'):
|
|
203
203
|
collection list Your collections (public_id = the HTTP door's address)
|
|
204
|
+
collection overview Each collection's site, state, posts, posts in Google, AI reads
|
|
204
205
|
collection new --name <n> [--description <t>] [--config '<json>'|--config-file cfg.json]
|
|
205
206
|
collection config <id> [--config '<json>'|--config-file cfg.json]
|
|
206
207
|
Print the ONE FILE (identity, content, cadence,
|
|
@@ -825,13 +826,15 @@ Sequences (multi-step cold email sent from your mailers; approving or enrolling
|
|
|
825
826
|
sequences get <sequence-id> Flow, enrollments, who replied at each step
|
|
826
827
|
sequences create --name <n> (--flow '<json>'|--flow-file <path>) [--mailer <mailer-id>]...
|
|
827
828
|
[--[no-]opt-out-footer] [--[no-]postal-address-footer] [--[no-]unsubscribe-links] [--[no-]detect-reply-opt-outs]
|
|
828
|
-
[--[no-]test-mode] [--
|
|
829
|
+
[--[no-]test-mode] [--default-lede <fallback opener line>]
|
|
830
|
+
[--send-window-start <HH:MM>] [--send-window-end <HH:MM>] [--send-window-timezone <IANA tz>]
|
|
829
831
|
New draft sequence (nothing sends yet; rails default on, opt-out line off;
|
|
830
832
|
sends 9:00-17:00 in each recipient's inferred timezone, else the sender's)
|
|
831
833
|
sequences update <sequence-id> [--name <n>] [--flow '<json>'|--flow-file <path>]
|
|
832
834
|
[--status draft|active|paused|archived] [--mailer <mailer-id>]...
|
|
833
835
|
[--[no-]opt-out-footer] [--[no-]postal-address-footer] [--[no-]unsubscribe-links] [--[no-]detect-reply-opt-outs]
|
|
834
|
-
[--[no-]test-mode] [--
|
|
836
|
+
[--[no-]test-mode] [--default-lede <fallback opener line>]
|
|
837
|
+
[--send-window-start <HH:MM>] [--send-window-end <HH:MM>] [--send-window-timezone <IANA tz>]
|
|
835
838
|
--test-mode (internal accounts only): walks as live, sends nothing
|
|
836
839
|
sequences pause|resume <sequence-id> Stop / restart sending
|
|
837
840
|
sequences enroll <sequence-id> (--list <list-id> | --email <addr>... | --recipients '<json>'|--recipients-file <path>)
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -445,6 +445,8 @@ async function cmdAdminTuningContext(ctx) {
|
|
|
445
445
|
* admin tuning picks <comparison-id> the blind queue (next pairs)
|
|
446
446
|
* admin tuning pick <comparison-id> --cell <key> --pick left|right|tie record a blind pick
|
|
447
447
|
* admin tuning reading-list <comparison-id> [--n 10] your next blind pairs as links, to read off the screen
|
|
448
|
+
* admin tuning archive <comparison-id> [--undo] take a read comparison out of the working list (or back); the record stays
|
|
449
|
+
* admin tuning comparisons [--archived only|all] the list; archived ones only when asked
|
|
448
450
|
* admin tuning pair <comparison-id> --cell <key> one pair named: live and candidate, both texts, the measures per arm
|
|
449
451
|
* admin tuning side-by-side <id>,<id>[,…] [--cell <key>] several comparisons as one board: each writer's measures against live, and one input's texts
|
|
450
452
|
* admin tuning candidates --kernels Hazel,Aspen|all --patch '{…}' [--base N] [--note "…"] the same changes as a candidate of each kernel
|
|
@@ -653,8 +655,18 @@ async function cmdAdminTuning(ctx) {
|
|
|
653
655
|
);
|
|
654
656
|
return json ? printResult(io, flags, r) : io.log(`comparison ${r.comparison?.id ?? r.id ?? ""} started`);
|
|
655
657
|
}
|
|
656
|
-
case "comparisons":
|
|
657
|
-
|
|
658
|
+
case "comparisons": {
|
|
659
|
+
const archived = flagStr(flags.archived);
|
|
660
|
+
const qs = archived ? `?${new URLSearchParams({ archived })}` : "";
|
|
661
|
+
return printResult(io, { ...flags, json: true }, await staffRequest(ctx, "GET", `${T}/comparisons${qs}`));
|
|
662
|
+
}
|
|
663
|
+
case "archive": {
|
|
664
|
+
if (!id) throw new CliError("Usage: admin tuning archive <comparison-id> [--undo]");
|
|
665
|
+
const r = await staffRequest(ctx, "POST", `${T}/comparisons/${id}/archive`, { archived: !flags.undo });
|
|
666
|
+
return json
|
|
667
|
+
? printResult(io, flags, r)
|
|
668
|
+
: io.log(`comparison ${id} ${flags.undo ? "back in the list" : "archived"}`);
|
|
669
|
+
}
|
|
658
670
|
case "comparison":
|
|
659
671
|
if (!id) throw new CliError("Usage: admin tuning comparison <id>");
|
|
660
672
|
return printResult(io, { ...flags, json: true }, await staffRequest(ctx, "GET", `${T}/comparisons/${id}`));
|
|
@@ -54,6 +54,7 @@ const TERMINAL = new Set(["published", "failed", "skipped", "cancelled"]);
|
|
|
54
54
|
*/
|
|
55
55
|
export const ARGS = {
|
|
56
56
|
list_collections: {},
|
|
57
|
+
get_collections_overview: {},
|
|
57
58
|
create_collection: {
|
|
58
59
|
name: { flag: "name", required: true },
|
|
59
60
|
description: "description",
|
|
@@ -153,11 +154,13 @@ export async function cmdCollection(ctx) {
|
|
|
153
154
|
return collectionCancel(rest);
|
|
154
155
|
case "inventory":
|
|
155
156
|
return collectionInventory(rest);
|
|
157
|
+
case "overview":
|
|
158
|
+
return collectionOverview(rest);
|
|
156
159
|
case "links":
|
|
157
160
|
return collectionLinks(rest);
|
|
158
161
|
default:
|
|
159
162
|
throw new CliError(
|
|
160
|
-
`Unknown collection subcommand: ${sub ?? "(none)"}. Try: list, new, config, delete, run, run-status, runs, approve, cancel, inventory, links`
|
|
163
|
+
`Unknown collection subcommand: ${sub ?? "(none)"}. Try: list, overview, new, config, delete, run, run-status, runs, approve, cancel, inventory, links`
|
|
161
164
|
);
|
|
162
165
|
}
|
|
163
166
|
}
|
|
@@ -168,6 +171,16 @@ async function collectionList(ctx) {
|
|
|
168
171
|
return 0;
|
|
169
172
|
}
|
|
170
173
|
|
|
174
|
+
// `collection overview` — each collection's site, state, posts, posts in Google and AI reads.
|
|
175
|
+
async function collectionOverview(ctx) {
|
|
176
|
+
const result = await ctx.client.callTool(
|
|
177
|
+
"get_collections_overview",
|
|
178
|
+
argsFromFlags(ARGS.get_collections_overview, ctx.flags)
|
|
179
|
+
);
|
|
180
|
+
printResult(ctx.io, ctx.flags, result);
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
|
|
171
184
|
async function collectionCreate(ctx) {
|
|
172
185
|
const result = await ctx.client.callTool(
|
|
173
186
|
"create_collection",
|
|
@@ -61,6 +61,8 @@ const SEQUENCE_RAIL_ARGS = {
|
|
|
61
61
|
detect_reply_opt_outs: { flag: "detect-reply-opt-outs", type: "bool", negate: "no-detect-reply-opt-outs" },
|
|
62
62
|
// Staff-only to turn on (the server refuses it for anyone else): walks as live, sends nothing.
|
|
63
63
|
test_mode: { flag: "test-mode", type: "bool", negate: "no-test-mode" },
|
|
64
|
+
// The fallback opener line for recipients with no opener (blank clears it on update).
|
|
65
|
+
default_lede: "default-lede",
|
|
64
66
|
};
|
|
65
67
|
|
|
66
68
|
// A send-window edge from --<flag> HH:MM (or a raw minute of day) → the
|