@letterstory/cli 0.120.0 → 0.121.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/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.120.0";
63
+ export const VERSION = "0.121.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
@@ -100,6 +100,8 @@ export const BOOLEAN_FLAGS = new Set([
100
100
  "dry-run",
101
101
  // admin crm record-outcome --draft
102
102
  "draft",
103
+ // admin crm reach-outs --fresh
104
+ "fresh",
103
105
  "prune",
104
106
  // org git sync --force
105
107
  "force",
@@ -769,7 +771,7 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
769
771
  | import <file.csv> [--vendor Concentrate] [--area A] [--ledger-key K] [--dry-run]
770
772
  | import <file.csv> [--vendor Concentrate] [--area A] [--keep-ledger-key] [--dry-run]
771
773
  | usage <events.json> per-call costs as kernels/lettertrace push them
772
- | remove <entry-id> | services | service <slug> [--owner …] [--monthly N|none] [--renewal D]
774
+ | remove <entry-id> | services | service <slug> [--owner …] [--monthly N|none] [--renewal D] [--units N|none]
773
775
  Where Letter's money goes (spending.letter.dev):
774
776
  totals, run rate, area/vendor/provider/model/
775
777
  key/operation/org breakdowns, every number's
@@ -795,6 +797,7 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
795
797
  [--at ISO] [--mrr-before N] [--mrr-after N] [--note "…"] [--save-offer …]
796
798
  [--save-result …] [--draft]
797
799
  | renewals [--days 90]
800
+ | reach-outs [--day YYYY-MM-DD] [--fresh] the day's reach-outs, N of 5 (#crm-reminders' count)
798
801
  | track-record [--since YYYY-MM-DD] | at-risk | expansion-signals
799
802
  | case <account-id> [--outcome <outcome-id>]
800
803
  | onboard <account-id> --domain acme.com [--name "Acme"] [--site "<direction>"]… [--sites N]
@@ -14,7 +14,7 @@
14
14
  // The old names — evals, eval-add, eval-set, proposals, propose-eval, capture-eval, reject-eval — still work.)
15
15
  // admin evals scoreboard|cases|runs|run|triage|guard|retire … (fleet:read / tuning:experiment)
16
16
  // admin fleet-experiments list|articles|clients|mark|unmark|new|assign|assign-eligible|assign-orgs|spin-up|apply|start|stop|decide … (fleet:read / fleet:experiment)
17
- // admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (crm:read / crm:write)
17
+ // admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|reach-outs|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (crm:read / crm:write)
18
18
  // admin spend summary|reconcile|pnl|entries|add|import|usage|remove|reference|stripe-sync|services|service … (spend:read / spend:write)
19
19
  // admin brand-detection <org-id> (fleet:read)
20
20
  // admin brand-detection <org-id> [--term t]... [--exact t]... [--exclude p]... [--note "…"] | --clear [--note "…"] (fleet:instrument)
@@ -3397,6 +3397,25 @@ async function cmdAdminCrm(ctx) {
3397
3397
  ].join("\n")
3398
3398
  );
3399
3399
  }
3400
+ case "reach-outs": {
3401
+ // admin crm reach-outs [--day YYYY-MM-DD] [--fresh] — the day's reach-out count toward
3402
+ // the target, the same number #crm-reminders posts (src/lib/crm/reach-out-day.ts).
3403
+ const params = new URLSearchParams(
3404
+ compact({ day: flagStr(flags.day), fresh: flagBool(flags.fresh) ? "1" : undefined })
3405
+ );
3406
+ return out(await staffRequest(ctx, "GET", `${CRM}/reach-outs/today?${params}`), (r) =>
3407
+ [
3408
+ `${r.day}: ${r.count} of ${r.target}${r.hit ? " — target hit" : ""}`,
3409
+ ...r.leads.map(
3410
+ (l) =>
3411
+ ` ${l.name} ${l.reachOuts.map((x) => `${x.channel}${x.byName || x.by ? ` by ${x.byName ?? "a teammate"}` : ""}`).join(", ")}`
3412
+ ),
3413
+ r.slack.unread
3414
+ ? `Slack: ${r.slack.unread} linked room${r.slack.unread === 1 ? "" : "s"} unread, so the count may be low`
3415
+ : `Slack: ${r.slack.read} room${r.slack.read === 1 ? "" : "s"} read`,
3416
+ ].join("\n")
3417
+ );
3418
+ }
3400
3419
  case "record-churn": {
3401
3420
  // admin crm record-churn <account-id> <reason> [--note "…"] [--at ISO] [--mrr-cents N]
3402
3421
  if (!id || !action) {
@@ -3629,7 +3648,7 @@ async function cmdAdminCrm(ctx) {
3629
3648
  }
3630
3649
  default:
3631
3650
  throw new CliError(
3632
- "Usage: admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (see --help)"
3651
+ "Usage: admin crm import|capture|outreach|signals|record|signal|accounts|account|score|slack-channels|link-slack|white-glove|set-white-glove|churn|revenue|reach-outs|record-churn|draft-churn-reason|undo-churn|outcomes|record-outcome|renewals|track-record|at-risk|expansion-signals|case|onboard|onboarding|retry-onboarding|onboard-plan|payment-link … (see --help)"
3633
3652
  );
3634
3653
  }
3635
3654
  }
@@ -4156,11 +4175,14 @@ async function cmdAdminSpend(ctx) {
4156
4175
  renewal_date: flagStr(flags.renewal),
4157
4176
  notes: flagStr(flags.notes),
4158
4177
  billing_source: oneOf(flags, "billing", ["api", "invoice", "unknown"]),
4178
+ units_purchased: flags.units === "none" ? undefined : flagNum(flags.units),
4179
+ unit_label: flagStr(flags["unit-label"]),
4159
4180
  });
4160
4181
  if (flags.monthly === "none") update.monthly_cost_usd = null;
4182
+ if (flags.units === "none") update.units_purchased = null;
4161
4183
  if (!slug || Object.keys(update).length === 0) {
4162
4184
  throw new CliError(
4163
- 'Usage: admin spend service <slug> [--owner "Steve"] [--plan "Pro"] [--monthly 20|none] [--renewal 2026-11-01] [--notes "…"] [--billing api|invoice|unknown]'
4185
+ 'Usage: admin spend service <slug> [--owner "Steve"] [--plan "Pro"] [--monthly 20|none] [--renewal 2026-11-01] [--notes "…"] [--billing api|invoice|unknown] [--units 30|none] [--unit-label "mailbox slots"]'
4164
4186
  );
4165
4187
  }
4166
4188
  const result = await staffRequest(ctx, "PATCH", `${SPEND}/services/${encodeURIComponent(slug)}`, update);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.120.0",
3
+ "version": "0.121.0",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",