@letterstory/cli 0.104.0 → 0.105.0

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 CHANGED
@@ -817,8 +817,8 @@ here can SEND email or spend money, so they refuse unknown flags instead of igno
817
817
  ```bash
818
818
  # Mailers
819
819
  letterstory mail vercel-key set --token-file - --team team_AbC123 # optional: buy domains on YOUR Vercel team (token on stdin)
820
- letterstory mail registrant --first-name Dana --last-name Lee --email d@acme.com --phone +1.4155550100 \
821
- --address "1 Main St" --city Oakland --state CA --zip 94607 --country US # WHOIS owner for purchases on that key
820
+ letterstory mail registrant --first-name Dana --last-name Lee --email d@acme.com --phone "(415) 555-0100" \
821
+ --address "1 Main St" --city Oakland --state CA --zip 94607 --country "United States" # WHOIS owner; any phone format
822
822
  letterstory mailers quote acme-mail.com # price it first: nothing is bought
823
823
  letterstory mailers launch acme-mail.com --mailer "hello:Hello Team" --forward-to me@acme.com --yes
824
824
  letterstory mailers domains # every domain: setup job, mailers, warmup
package/lib/cli.mjs CHANGED
@@ -60,7 +60,7 @@ import {
60
60
  } from "./commands.mjs";
61
61
 
62
62
  // Keep in sync with cli/package.json.
63
- export const VERSION = "0.104.0";
63
+ export const VERSION = "0.105.0";
64
64
 
65
65
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
66
66
  // can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
@@ -186,6 +186,8 @@ export const BOOLEAN_FLAGS = new Set([
186
186
  "no-postal-address-footer",
187
187
  // `mailers launch … --no-warmup` / `--warmup` / `--consent`: value-less switches.
188
188
  "no-warmup",
189
+ "move-vercel-key",
190
+ "keep-vercel-key",
189
191
  "warmup",
190
192
  "consent",
191
193
  "no-redesign",
@@ -1108,6 +1110,9 @@ Mailers (the sending mailboxes):
1108
1110
  Buy or reuse the domain, create mailers, warm them up
1109
1111
  (a net-new domain is a real, auto-renewing purchase)
1110
1112
  mailers domains Every domain you own: mail status, setup job, mailers
1113
+ mailers move <owned-domain-id> --to <org-id> --yes [--keep-vercel-key]
1114
+ Move a domain, its setup and mailers to another org you
1115
+ admin (with this org's Vercel key unless --keep-vercel-key)
1111
1116
  mailers list [--domain <apex>] Your mailers + status + daily send limit
1112
1117
  mailers domain <owned-domain-id> Provisioning stage, DNS state, mailers on a domain
1113
1118
  mailers messages <mailer-id> [--folder all|inbox|sent] [--limit <n>]
@@ -1129,9 +1134,10 @@ Mail:
1129
1134
  mail vercel-key set (--token <t> | --token-file <path|->) [--team <team_id>]
1130
1135
  Buy and own mail domains on your Vercel account / team
1131
1136
  mail vercel-key remove --yes Future purchases go back to Letterstory's account
1132
- mail registrant --first-name <f> --last-name <l> --email <e> --phone +1.4155551234
1133
- --address <a> [--address2 <a>] --city <c> --state <s> --zip <z> --country US [--company <c>]
1137
+ mail registrant --first-name <f> --last-name <l> --email <e> --phone "(415) 555-1234"
1138
+ --address <a> [--address2 <a>] --city <c> --state <s> --zip <z> --country "United States" [--company <c>]
1134
1139
  WHOIS registrant for purchases on your Vercel key
1140
+ (any phone format; country as a name or a 2-letter code)
1135
1141
 
1136
1142
  Insights:
1137
1143
  insights summary [--period …] [--part <block>]... Measure Overview: AI named/cited rates, share of voice, search, targets
@@ -1170,6 +1176,7 @@ The Site (one model of your whole marketing site, keyed by host and path):
1170
1176
  Repo changes (Claude Code edits your repo in a sandbox; the Letterstory GitHub App opens a PR):
1171
1177
  repo repos Repos the Letterstory GitHub App can reach
1172
1178
  repo branches --repo owner/name Branches a change can start from (default first)
1179
+ repo prs [--repo owner/name] Every open PR (whoever opened it), longest-idle first
1173
1180
  repo suggestions Fixes found and not acted on yet, and how to start each
1174
1181
  repo settings [--action build|build_pr|slack] [--branch <name>|none] [--slack-agent <name|U…>|none]
1175
1182
  [--slack-channel <C…>|none]
@@ -394,6 +394,11 @@ export const ARGS = {
394
394
  mail_postal_address: { positional: 0, label: "address", required: true },
395
395
  },
396
396
  list_mail_domains: {},
397
+ move_mail_domain: {
398
+ owned_domain_id: { positional: 0, label: "owned-domain-id", required: true },
399
+ to_org_id: { flag: "to", required: true },
400
+ move_vercel_key: { flag: "move-vercel-key", type: "bool", negate: "keep-vercel-key" },
401
+ },
397
402
  quote_mail_domain: {
398
403
  domain: { positional: 0, label: "domain", required: true },
399
404
  },
@@ -693,7 +698,7 @@ async function prospectsColumns(ctx, sub) {
693
698
  }
694
699
  }
695
700
 
696
- const MAILERS_USAGE = `Usage: mailers <list|domains|domain|quote|launch|messages|message|forward|warmup|limit|retire|suppressions>`;
701
+ const MAILERS_USAGE = `Usage: mailers <list|domains|domain|quote|launch|move|messages|message|forward|warmup|limit|retire|suppressions>`;
697
702
 
698
703
  export async function cmdMailers(ctx) {
699
704
  const sub = ctx.positionals[0];
@@ -708,6 +713,21 @@ export async function cmdMailers(ctx) {
708
713
  return run(rest, "get_mailer_domain_status");
709
714
  case "quote":
710
715
  return run(rest, "quote_mail_domain");
716
+ case "move": {
717
+ // Re-homes the domain, its mailers and (by default) the org's Vercel key: confirm first.
718
+ if (!rest.flags.yes) {
719
+ const id = flagStr(rest.positionals[0]) ?? "<owned-domain-id>";
720
+ ctx.io.error(
721
+ `Moving re-homes the domain, its setup and mailers (and this org's Vercel key unless --keep-vercel-key) in the other organization. Re-run with --yes to confirm: ${ctx.bin} mailers move ${id} --to <org-id> --yes`
722
+ );
723
+ return 1;
724
+ }
725
+ return run(
726
+ rest,
727
+ "move_mail_domain",
728
+ (r) => `Moved ${r?.domain ?? "the domain"} to ${r?.to_org_id ?? "the other organization"}.`
729
+ );
730
+ }
711
731
  case "launch": {
712
732
  // A net-new domain is a real purchase, so a launch needs --yes (quote it first).
713
733
  if (!rest.flags.yes) {
@@ -4,6 +4,7 @@
4
4
  // repo list → list_repo_changes repo cancel → cancel_repo_change
5
5
  // repo publish → publish_repo_change (Make PR on a preview)
6
6
  // repo repos → list_github_app_repos repo branches → list_repo_branches
7
+ // repo prs → list_open_pull_requests (every open PR, whoever opened it)
7
8
  // repo install-letterprove → letterprove_open_install_pr
8
9
  // repo suggestions → list_suggested_fixes
9
10
  // repo settings → get_repo_change_settings, or set_repo_change_settings with --action / --branch
@@ -109,6 +110,10 @@ const ARGS = {
109
110
  repo_owner: { value: (flags) => splitRepo(flags).owner },
110
111
  repo_name: { value: (flags) => splitRepo(flags).name },
111
112
  },
113
+ list_open_pull_requests: {
114
+ repo_owner: { value: (flags) => (flags.repo === undefined ? undefined : splitRepo(flags).owner) },
115
+ repo_name: { value: (flags) => (flags.repo === undefined ? undefined : splitRepo(flags).name) },
116
+ },
112
117
  };
113
118
 
114
119
  const TERMINAL = new Set(["succeeded", "no_changes", "failed", "cancelled"]);
@@ -154,6 +159,8 @@ export async function cmdRepo(ctx) {
154
159
  return repoRepos(rest);
155
160
  case "branches":
156
161
  return repoBranches(rest);
162
+ case "prs":
163
+ return repoPrs(rest);
157
164
  case "settings":
158
165
  return repoSettings(rest);
159
166
  case "suggestions":
@@ -164,7 +171,7 @@ export async function cmdRepo(ctx) {
164
171
  return repoSlackTest(rest);
165
172
  default:
166
173
  throw new CliError(
167
- `Unknown repo subcommand: ${sub ?? "(none)"}. Try: start, fix-audit, install-letterprove, sites, set-site, reset-site, status, list, publish, cancel, repos, branches, settings, suggestions, slack-targets, slack-test`
174
+ `Unknown repo subcommand: ${sub ?? "(none)"}. Try: start, fix-audit, install-letterprove, sites, set-site, reset-site, status, list, publish, cancel, repos, branches, prs, settings, suggestions, slack-targets, slack-test`
168
175
  );
169
176
  }
170
177
  }
@@ -401,6 +408,24 @@ async function repoRepos(ctx) {
401
408
  return 0;
402
409
  }
403
410
 
411
+ /** `repo prs [--repo owner/name]`: every open PR, longest-idle first, and which Letterstory opened. */
412
+ async function repoPrs(ctx) {
413
+ const { client, flags, io } = ctx;
414
+ refuseUnknownFlags(ctx, {}, ["repo"]);
415
+ const result = await client.callTool("list_open_pull_requests", argsFromFlags(ARGS.list_open_pull_requests, flags));
416
+ printResult(io, flags, result, (r) =>
417
+ r.pullRequests.length === 0
418
+ ? "No open pull requests."
419
+ : r.pullRequests
420
+ .map(
421
+ (p) =>
422
+ `${p.repo}#${p.number} ${p.title} (${p.daysSinceUpdate}d idle${p.draft ? ", draft" : ""}${p.letterRun ? `, Letterstory run ${p.letterRun.status}` : ""})\n ${p.url}`
423
+ )
424
+ .join("\n")
425
+ );
426
+ return 0;
427
+ }
428
+
404
429
  /** `repo branches --repo owner/name`: the branches a run can start from, default first. */
405
430
  async function repoBranches(ctx) {
406
431
  const { client, flags, io } = ctx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.104.0",
3
+ "version": "0.105.0",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",