@letterstory/cli 0.108.1 → 0.108.2
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 +1 -1
- package/lib/commands/admin.mjs +19 -1
- package/package.json +1 -1
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.108.
|
|
63
|
+
export const VERSION = "0.108.2";
|
|
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
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -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|record-churn|undo-churn|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|record-churn|undo-churn|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)
|
|
@@ -3325,6 +3325,24 @@ async function cmdAdminCrm(ctx) {
|
|
|
3325
3325
|
].join("\n")
|
|
3326
3326
|
);
|
|
3327
3327
|
}
|
|
3328
|
+
case "revenue": {
|
|
3329
|
+
// admin crm revenue — monthly NRR/GRR since 2026-08-10, the bridge, spend per client (docs/architecture/retention.md).
|
|
3330
|
+
const pct = (x) => (x == null ? "—" : `${(x * 100).toFixed(1)}%`);
|
|
3331
|
+
const usd = (cents) => `$${Math.round(cents / 100).toLocaleString("en-US")}`;
|
|
3332
|
+
return out(await staffRequest(ctx, "GET", `${CRM}/revenue`), (r) =>
|
|
3333
|
+
[
|
|
3334
|
+
r.headline
|
|
3335
|
+
? `${r.headline.month}: NRR ${pct(r.headline.nrr)} · GRR ${pct(r.headline.grr)} · expansion ${usd(r.headline.expansionCents)} · avg ${r.headline.avgCents == null ? "—" : usd(r.headline.avgCents)}/client`
|
|
3336
|
+
: "No complete month yet.",
|
|
3337
|
+
`Clients counted: ${r.coverage.counted} (${r.coverage.stripe} Stripe, ${r.coverage.deal} deal) · comp ${r.coverage.comp} · ${usd(r.coverage.countedCents)}/mo`,
|
|
3338
|
+
"",
|
|
3339
|
+
...r.periods.map(
|
|
3340
|
+
(p) =>
|
|
3341
|
+
`${p.month}${p.partial ? " (partial)" : ""}${p.estimated ? " ~" : ""} ${usd(p.startCents)} → ${usd(p.endCents)} NRR ${pct(p.nrr)} +new ${usd(p.moves.new)} +back ${usd(p.moves.reactivated)} +exp ${usd(p.moves.expansion)} −con ${usd(p.moves.contraction)} −churn ${usd(p.moves.churn)} ±reclassified ${usd(p.moves.reclassified)}`
|
|
3342
|
+
),
|
|
3343
|
+
].join("\n")
|
|
3344
|
+
);
|
|
3345
|
+
}
|
|
3328
3346
|
case "record-churn": {
|
|
3329
3347
|
// admin crm record-churn <account-id> <reason> [--note "…"] [--at ISO] [--mrr-cents N]
|
|
3330
3348
|
if (!id || !action) {
|