@letterstory/cli 0.149.1 → 0.150.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/lib/cli.mjs CHANGED
@@ -66,7 +66,7 @@ import {
66
66
 
67
67
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
68
68
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
69
- export const VERSION = "0.149.1";
69
+ export const VERSION = "0.150.1";
70
70
 
71
71
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
72
72
  // can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
@@ -969,7 +969,7 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
969
969
  | provision <org-id> --plan starter|growth|scale [--ratio 1|2|4|8 (8 needs --why "…")] [--complimentary N] [--stripe-customer cus_…] [--start ISO] [--review D]
970
970
  | reconcile [--org <org-id>] | forward
971
971
  | payments [--org <org-id>] [--open] | payments retry <lago-invoice-id> | payments run [--dry]
972
- | signups [--status open|card_saved|provisioned|paid|abandoned]
972
+ | signups [--status open|card_saved|provisioned|paid|abandoned|canceled]
973
973
  | cap <org-id> <dollars|off> [--why "…"] | cancel <org-id> --why "…" --yes
974
974
  | move <org-id> --plan starter|growth|scale [--ratio N [--why "…"]] [--reason "…"] [--stripe-subscription sub_…] [--dry]
975
975
  | changes [--org <org-id>] | changes cancel <org-id>
@@ -1130,10 +1130,11 @@ Seers (event-driven signals -> drafts):
1130
1130
  org export --split <dir> …as one file per record (for keeping config in git)
1131
1131
  org join <dir> [--file <path>] Rebuild the bundle from a --split directory
1132
1132
  org integrations Every integration and whether it's connected
1133
- org billing [cap <dollars|off> [--why "…"] | request [--note "…"] | cancel [--why "…"] --yes]
1133
+ org billing [cap <dollars|off> [--why "…"] | card | request [--note "…"] | cancel [--why "…"] --yes]
1134
1134
  Usage billing: plan, this period against the
1135
1135
  allowance and spend cap, failed payments; set
1136
- the cap (admins) or ask the admins for more
1136
+ the cap or change the card (admins), or ask
1137
+ the admins for more
1137
1138
  org billing usage This period by product and collection: quantities,
1138
1139
  and tokens and dollars when billed by usage
1139
1140
  org linear [teams [--team <id|key>] | set --team <id|key> [--project <id>|none] | disconnect]
@@ -1445,6 +1446,7 @@ The Site (one model of your whole marketing site, keyed by host and path):
1445
1446
 
1446
1447
  Repo changes (Claude Code edits your repo in a sandbox; the Letter GitHub App opens a PR):
1447
1448
  repo repos Repos the Letter GitHub App can reach
1449
+ repo connect Is GitHub connected; the link a person opens to connect it
1448
1450
  repo branches --repo owner/name Branches a change can start from (default first)
1449
1451
  repo prs [--repo owner/name] Every open PR (whoever opened it), longest-idle first
1450
1452
  repo suggestions Fixes found and not acted on yet, and how to start each
@@ -1502,7 +1504,7 @@ Repo changes (Claude Code edits your repo in a sandbox; the Letter GitHub App op
1502
1504
  repo merge <run-id> Merge its open PR (a squash; the repo's branch rules decide)
1503
1505
  repo revise <run-id> --instructions <text>|--instructions-file <path|->
1504
1506
  Ask for more on a preview; it takes over the preview's link
1505
- repo cancel <run-id> Stop it and delete the sandbox; no PR (Discard a preview)
1507
+ repo cancel <run-id> [--force] Stop it and delete the sandbox; no PR (Discard a preview)
1506
1508
 
1507
1509
  Feedback (tell us what's broken, missing, unclear, or wanted):
1508
1510
  feedback submit --category bug|missing_feature|unclear|feature_request|praise|other
@@ -5213,7 +5213,7 @@ const LAGO_USAGE = `Usage: admin billing lago <command>
5213
5213
  payments [--org <org-id>] [--open] failed payments and what the retry loop did about each
5214
5214
  payments retry <lago-invoice-id> charge one failed invoice again now
5215
5215
  payments run [--dry] one pass of the failed-payment loop now (--dry: report only)
5216
- signups [--status open|card_saved|provisioned|paid|abandoned] new paying orgs on their way onto Lago
5216
+ signups [--status open|card_saved|provisioned|paid|abandoned|canceled] new paying orgs on their way onto Lago
5217
5217
  cap <org-id> <dollars|off> [--why "…"] set an account's monthly spend cap on overage (off: no cap)
5218
5218
  cancel <org-id> --why "…" --yes end an account's Lago plan now and refund its first invoice
5219
5219
  move <org-id> --plan starter [--ratio 4] [--why "…" above 4x] [--reason "…"] [--complimentary 20000] [--review 2027-05-01] [--stripe-subscription sub_…] [--dry]
@@ -18,6 +18,7 @@ export const ARGS = {
18
18
  },
19
19
  suggest_starter_automations: {
20
20
  collection_id: { flag: "collection", required: true },
21
+ ground: { flag: "ground", enum: ["answers", "search"] },
21
22
  },
22
23
  get_ground_measures: {
23
24
  collection_id: { flag: "collection", required: true },
@@ -35,6 +35,7 @@ export const ARGS = {
35
35
  },
36
36
  request_billing_tokens: { note: { flag: "note" } },
37
37
  cancel_billing_plan: { reason: { flag: "why" } },
38
+ update_billing_card: {},
38
39
  list_integrations: {},
39
40
  get_linear_connection: {},
40
41
  list_linear_targets: { team_id: { flag: "team" } },
@@ -111,7 +112,8 @@ const usd = (n) => `$${Number(n).toFixed(2)}`;
111
112
  /**
112
113
  * `org billing`: the org's plan on Lago, this period against its allowance and spend cap, whether
113
114
  * it is past due, and its failed payments (get_billing_payments). `org billing cap <dollars|off>`
114
- * sets the cap (set_billing_spend_cap, admins); `org billing request` asks the admins for more
115
+ * sets the cap (set_billing_spend_cap, admins); `org billing card` links to Stripe's page for a new
116
+ * card (update_billing_card, admins); `org billing request` asks the admins for more
115
117
  * (request_billing_tokens); `org billing usage` is this period by product and collection (get_billing).
116
118
  */
117
119
  async function orgBilling(ctx) {
@@ -130,14 +132,30 @@ async function orgBilling(ctx) {
130
132
  if (positionals[0] === "cancel") {
131
133
  refuseUnknownFlags(ctx, ARGS.cancel_billing_plan, ["yes"]);
132
134
  if (!flagBool(flags.yes))
133
- throw new CliError("This ends the plan now and refunds its first invoice. Run again with --yes to do it.");
135
+ throw new CliError(
136
+ "This ends the plan now and refunds its first invoice (and any overage charged this month). Run again with --yes to do it."
137
+ );
134
138
  const result = await client.callTool("cancel_billing_plan", argsFromFlags(ARGS.cancel_billing_plan, flags, []));
135
139
  printResult(io, flags, result, (r) =>
136
- r.firstInvoice === "refunded"
137
- ? `Plan cancelled; $${(r.refundedCents / 100).toFixed(2)} refunded to the card.`
138
- : r.firstInvoice === "voided"
139
- ? "Plan cancelled; its unpaid first invoice is voided."
140
- : "Plan cancelled."
140
+ [
141
+ "Plan cancelled",
142
+ r.firstInvoice === "voided" ? "; its unpaid first invoice is voided" : "",
143
+ r.refundedCents ? `; $${(r.refundedCents / 100).toFixed(2)} refunded to the card` : "",
144
+ r.topUpsRefundedCents ? ` ($${(r.topUpsRefundedCents / 100).toFixed(2)} of it overage)` : "",
145
+ ".",
146
+ ].join("")
147
+ );
148
+ return 0;
149
+ }
150
+ if (positionals[0] === "card") {
151
+ refuseUnknownFlags(ctx, ARGS.update_billing_card, []);
152
+ const result = await client.callTool("update_billing_card", argsFromFlags(ARGS.update_billing_card, flags, []));
153
+ printResult(
154
+ io,
155
+ flags,
156
+ result,
157
+ (r) =>
158
+ `Enter the new card here${r.expiresAt ? ` (until ${r.expiresAt})` : ""}:\n${r.url}\nIt becomes the card we charge, and any failed plan invoice is charged to it.`
141
159
  );
142
160
  return 0;
143
161
  }
@@ -8,6 +8,7 @@
8
8
  // repo revise → revise_repo_change (ask for more on a preview, before the PR)
9
9
  // repo say → send_repo_change_message (steer a build while its agent works)
10
10
  // repo repos → list_github_app_repos repo branches → list_repo_branches
11
+ // repo connect → connect_github (the link a person opens to connect GitHub)
11
12
  // repo prs → list_open_pull_requests (every open PR, whoever opened it)
12
13
  // repo install-letterprove → letterprove_open_install_pr
13
14
  // repo install-visitors → visitors_open_install_pr
@@ -221,7 +222,11 @@ const ARGS = {
221
222
  value: (flags, positionals) => flagStr(flags.message) ?? (positionals.slice(1).join(" ") || undefined),
222
223
  },
223
224
  },
224
- cancel_repo_change: { run_id: { positional: 0, required: true, label: "run-id" } },
225
+ cancel_repo_change: {
226
+ run_id: { positional: 0, required: true, label: "run-id" },
227
+ // --force: cancel a change another key or person started.
228
+ force: { flag: "force", type: "bool" },
229
+ },
225
230
  publish_repo_change: { run_id: { positional: 0, required: true, label: "run-id" } },
226
231
  merge_repo_change: { run_id: { positional: 0, required: true, label: "run-id" } },
227
232
  revise_repo_change: {
@@ -245,6 +250,7 @@ const ARGS = {
245
250
  site_host: "site",
246
251
  },
247
252
  list_github_app_repos: {},
253
+ connect_github: {},
248
254
  list_repo_branches: {
249
255
  repo_owner: { value: (flags) => splitRepo(flags).owner },
250
256
  repo_name: { value: (flags) => splitRepo(flags).name },
@@ -329,6 +335,8 @@ export async function cmdRepo(ctx) {
329
335
  return repoSay(rest);
330
336
  case "repos":
331
337
  return repoRepos(rest);
338
+ case "connect":
339
+ return repoConnect(rest);
332
340
  case "branches":
333
341
  return repoBranches(rest);
334
342
  case "prs":
@@ -713,6 +721,14 @@ async function repoRepos(ctx) {
713
721
  return 0;
714
722
  }
715
723
 
724
+ /** `repo connect`: whether GitHub is connected, and the link a person opens to connect it. */
725
+ async function repoConnect(ctx) {
726
+ const { client, flags, io } = ctx;
727
+ const result = await client.callTool("connect_github", argsFromFlags(ARGS.connect_github, flags));
728
+ printResult(io, flags, result, (r) => r.message);
729
+ return 0;
730
+ }
731
+
716
732
  /** `repo prs [--repo owner/name]`: every open PR, longest-idle first, and which Letter opened. */
717
733
  async function repoPrs(ctx) {
718
734
  const { client, flags, io } = ctx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.149.1",
3
+ "version": "0.150.1",
4
4
  "description": "Spin up and manage Letter phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",