@letterstory/cli 0.147.0 → 0.148.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
@@ -65,7 +65,7 @@ import {
65
65
 
66
66
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
67
67
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
68
- export const VERSION = "0.147.0";
68
+ export const VERSION = "0.148.0";
69
69
 
70
70
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
71
71
  // can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
@@ -1107,6 +1107,8 @@ Seers (event-driven signals -> drafts):
1107
1107
  Usage billing: plan, this period against the
1108
1108
  allowance and spend cap, failed payments; set
1109
1109
  the cap (admins) or ask the admins for more
1110
+ org billing usage This period by product and collection: quantities,
1111
+ and tokens and dollars when billed by usage
1110
1112
  org linear [teams [--team <id|key>] | set --team <id|key> [--project <id>|none] | disconnect]
1111
1113
  Where Letter files Linear issues (connect in Settings)
1112
1114
  org diff <file|dir> What applying a bundle would change (reads only)
@@ -28,6 +28,7 @@ export const ARGS = {
28
28
  describe_org_config_fields: {},
29
29
  get_org_config_source: {},
30
30
  get_billing_payments: {},
31
+ get_billing: {},
31
32
  set_billing_spend_cap: {
32
33
  cap_usd: { value: (_flags, positionals) => capFrom(requirePositional(positionals, 0, "dollars|off")) },
33
34
  reason: { flag: "why" },
@@ -111,7 +112,7 @@ const usd = (n) => `$${Number(n).toFixed(2)}`;
111
112
  * `org billing`: the org's plan on Lago, this period against its allowance and spend cap, whether
112
113
  * it is past due, and its failed payments (get_billing_payments). `org billing cap <dollars|off>`
113
114
  * sets the cap (set_billing_spend_cap, admins); `org billing request` asks the admins for more
114
- * (request_billing_tokens).
115
+ * (request_billing_tokens); `org billing usage` is this period by product and collection (get_billing).
115
116
  */
116
117
  async function orgBilling(ctx) {
117
118
  const { client, flags, io, positionals } = ctx;
@@ -149,6 +150,12 @@ async function orgBilling(ctx) {
149
150
  printResult(io, flags, result, (r) => `Asked ${r.emailedTo} admin${r.emailedTo === 1 ? "" : "s"} for more.`);
150
151
  return 0;
151
152
  }
153
+ if (positionals[0] === "usage") {
154
+ refuseUnknownFlags(ctx, ARGS.get_billing, []);
155
+ const result = await client.callTool("get_billing", argsFromFlags(ARGS.get_billing, flags, []));
156
+ printResult(io, flags, result, billingUsageText);
157
+ return 0;
158
+ }
152
159
  refuseUnknownFlags(ctx, {}, []);
153
160
  const result = await client.callTool("get_billing_payments", {});
154
161
  printResult(io, flags, result, (r) =>
@@ -180,6 +187,29 @@ async function orgBilling(ctx) {
180
187
  return 0;
181
188
  }
182
189
 
190
+ const tokensOrQty = (p) => `${p.billableQuantity}${p.tokens === null ? "" : ` ${p.tokens} tokens`}`;
191
+
192
+ /** `org billing usage` as text: the period, the totals, then each product and each collection. */
193
+ function billingUsageText(r) {
194
+ const lines = [
195
+ `${r.plan ? `Plan: ${r.plan.name}${r.plan.ratio !== 1 ? ` (${r.plan.ratio}x)` : ""}. ` : ""}This period: ${r.period.from.slice(0, 10)} to ${r.period.to.slice(0, 10)}${r.period.basis === "ours" ? " (Lago unreadable: our own rating)" : ""}.`,
196
+ ];
197
+ if (r.tokens)
198
+ lines.push(
199
+ `Tokens: ${r.tokens.used} used of ${r.tokens.allowance} included${r.tokens.complimentary ? ` (+${r.tokens.complimentary} complimentary)` : ""}${r.tokens.arriving ? ` (${r.tokens.arriving} of them still being counted)` : ""}${r.tokens.running ? `, ${r.tokens.running} held by running work` : ""}.`
200
+ );
201
+ else lines.push("Not billed by usage: quantities only.");
202
+ if (r.usd) lines.push(`Plan fee ${usd(r.usd.planFee)}; overage so far ${usd(r.usd.overage)}.`);
203
+ if (r.byProduct.length === 0) return [...lines, "No usage this period."].join("\n");
204
+ lines.push("", "By product:", ...r.byProduct.map((p) => ` ${p.label} ${tokensOrQty(p)}`));
205
+ lines.push("", "By collection:");
206
+ for (const c of r.byCollection) {
207
+ lines.push(` ${c.name}${c.tokens === null ? "" : ` ${c.tokens} tokens`}`);
208
+ for (const p of c.products) lines.push(` ${p.label} ${tokensOrQty(p)}`);
209
+ }
210
+ return lines.join("\n");
211
+ }
212
+
183
213
  /** `org fields [section]`: what each setting in the bundle means (describe_org_config_fields). */
184
214
  async function orgFields(ctx) {
185
215
  const { client, flags, io, positionals } = ctx;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.147.0",
3
+ "version": "0.148.0",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",