@letterstory/cli 0.177.24 → 0.177.26

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
@@ -88,7 +88,7 @@ import {
88
88
  import { fetchParkedSections, withoutParked } from "./parked.mjs";
89
89
 
90
90
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
91
- export const VERSION = "0.177.24";
91
+ export const VERSION = "0.177.26";
92
92
 
93
93
  /** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
94
94
  export const EXIT_PAYMENT_REQUIRED = 3;
@@ -97,6 +97,9 @@ export const EXIT_PAYMENT_REQUIRED = 3;
97
97
  // can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
98
98
  // `negate` spelling) in a command's ARGS map must be listed; boolean-flags.test.ts enforces it.
99
99
  export const BOOLEAN_FLAGS = new Set([
100
+ // visits export: only the people or companies who fit the ICP, or only those who don't.
101
+ "icp",
102
+ "not-icp",
100
103
  // org mcp add: the server signs in with OAuth instead of a header value.
101
104
  "sign-in",
102
105
  // collection onboard: connect without drafting or scheduling.
@@ -1358,7 +1361,7 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
1358
1361
  | payments [--org <org-id>] [--open] | payments retry <lago-invoice-id> | payments run [--dry]
1359
1362
  | signups [--status open|card_saved|provisioned|paid|abandoned|canceled]
1360
1363
  | cap <org-id> <dollars|off> [--why "…"] | cancel <org-id> --why "…" --yes
1361
- | move <org-id> --plan starter|growth|scale [--ratio N [--why "…"]] [--reason "…"] [--stripe-subscription sub_…] [--dry]
1364
+ | move <org-id> --plan starter|growth|scale [--ratio N [--why "…"]] [--reason "…"] [--stripe-subscription sub_…] [--now] [--dry]
1362
1365
  | changes [--org <org-id>] | changes cancel <org-id>
1363
1366
  Usage billing on Lago: the plan catalog, an org's
1364
1367
  plan and gifted ratio, Lago's tokens against ours,
@@ -2005,6 +2008,8 @@ Visits (Visitors: AI agents reading your site, and AI answers sending people to
2005
2008
  visits [--agent <a>] [--since 7d] [--path '/docs/*'] [--purpose live|index|training|automated_browser] [--kind page|agent_file|site_file|asset] [--paths <n>] [--site <id>]
2006
2009
  Agent visits: per agent, why they came, most-read paths by kind
2007
2010
  visits citations [--since 30d] [--site <id>] Visits that clicked through from ChatGPT, Claude, Perplexity…
2011
+ visits who [--icp|--not-icp] [--category <group>] [--path <p>] [--since 30d] [--limit <n>]
2012
+ Who was identified, and who fits your ICP
2008
2013
  visits compare <agent-a> <agent-b> [--since 7d] [--path '/docs/*'] [--purpose <p>]
2009
2014
  Pages one agent read that the other didn't
2010
2015
  visits export [--since 30d] [--format json|csv] [--table agent_visits|citations]
@@ -6254,8 +6254,8 @@ const LAGO_USAGE = `Usage: admin billing desk [--json] the Billing desk: s
6254
6254
  signups end <org-id> --why "…" end an org's signup in flight (not yet provisioned), so one on other terms can open
6255
6255
  cap <org-id> <dollars|off> [--why "…"] set an account's monthly spend cap on overage (off: no cap)
6256
6256
  cancel <org-id> --why "…" --yes end an account's Lago plan now (its plan fee refunded in its first month, once per org)
6257
- move <org-id> --plan starter [--ratio 4] [--why "…" above 4x] [--reason "…"] [--complimentary 20000] [--review 2027-05-01] [--stripe-subscription sub_…] [--dry]
6258
- move an existing customer from Stripe to Lago at their renewal
6257
+ move <org-id> --plan starter [--ratio 4] [--why "…" above 4x] [--reason "…"] [--complimentary 20000] [--review 2027-05-01] [--stripe-subscription sub_…] [--now] [--dry]
6258
+ move an existing customer from Stripe to Lago at their renewal (--now: today, the first invoice credited)
6259
6259
  changes [--org <org-id>] term changes waiting to take effect (moves, cheaper plans, new ratios)
6260
6260
  changes cancel <org-id> take back an org's scheduled change before it takes effect`;
6261
6261
 
@@ -6893,13 +6893,17 @@ async function cmdAdminBilling(ctx) {
6893
6893
  complimentaryTokens: flagNum(flags.complimentary),
6894
6894
  reviewAt: flagStr(flags.review),
6895
6895
  stripeSubscriptionId: flagStr(flags["stripe-subscription"]),
6896
+ startNow: flags.now ? true : undefined,
6896
6897
  dryRun: flags.dry ? true : undefined,
6897
6898
  })
6898
6899
  );
6899
6900
  const p = result.plan;
6901
+ const credit = p.to.firstInvoiceCreditCents ?? 0;
6900
6902
  ok(
6901
6903
  ctx,
6902
- `${result.dryRun ? "Would move" : "Moving"} ${p.orgId} from Stripe ${p.from.stripeSubscriptionId} (${p.from.product ?? "subscription"}) to Lago ${p.to.plan} at its renewal ${p.from.renewsAt}: Stripe stops then, Lago charges $${(p.to.amountCents / 100).toFixed(2)} then (${p.to.includedTokens} tokens included, overage $${p.to.overageUsdPerToken} a token). Bonus when it takes effect: ${(p.to.bonusTokens ?? 0).toLocaleString("en-US")} tokens (signup × ${p.to.ratio}x), once.`
6904
+ p.to.startsAt && p.to.startsAt !== p.from.renewsAt
6905
+ ? `${result.dryRun ? "Would move" : "Moving"} ${p.orgId} from Stripe ${p.from.stripeSubscriptionId} (${p.from.product ?? "subscription"}) to Lago ${p.to.plan} now: ${p.to.includedTokens} tokens from today, the first invoice $${((p.to.amountCents - credit) / 100).toFixed(2)} after $${(credit / 100).toFixed(2)} Stripe already took. Stripe stops at ${p.from.renewsAt}, when Lago charges $${(p.to.amountCents / 100).toFixed(2)} next.`
6906
+ : `${result.dryRun ? "Would move" : "Moving"} ${p.orgId} from Stripe ${p.from.stripeSubscriptionId} (${p.from.product ?? "subscription"}) to Lago ${p.to.plan} at its renewal ${p.from.renewsAt}: Stripe stops then, Lago charges $${(p.to.amountCents / 100).toFixed(2)} then (${p.to.includedTokens} tokens included, overage $${p.to.overageUsdPerToken} a token). Bonus when it takes effect: ${(p.to.bonusTokens ?? 0).toLocaleString("en-US")} tokens (signup × ${p.to.ratio}x), once.`
6903
6907
  );
6904
6908
  printResult(io, flags, result);
6905
6909
  return 0;
@@ -9,6 +9,7 @@
9
9
  // letterstory visits compare chatgpt claude --path '/docs/*' --since 7d
10
10
  // letterstory visits citations --since 30d
11
11
  // letterstory visits people --since 30d [--path /pricing] people who read the site, and how many were identified
12
+ // letterstory visits who --icp [--category Investors] [--path /pricing] who was identified (--icp: who fits your ICP)
12
13
  // letterstory visits export --since 30d --format csv
13
14
  // letterstory visits sites
14
15
  // letterstory visits domain composal.com [--site <id>] move the site to a new domain, keeping its key
@@ -43,6 +44,14 @@ export const ARGS = {
43
44
  },
44
45
  visitors_get_citations: { site_id: "site", days },
45
46
  visitors_get_human_visits: { site_id: "site", days, path: "path" },
47
+ visitors_get_people: {
48
+ site_id: "site",
49
+ days,
50
+ path: "path",
51
+ category: "category",
52
+ limit: { flag: "limit", type: "num" },
53
+ icp: { flag: "icp", type: "bool", negate: "not-icp" },
54
+ },
46
55
  visitors_admin_coverage: { site_id: "site" },
47
56
  visitors_add_connector: {
48
57
  site_id: "site",
@@ -99,6 +108,8 @@ export async function cmdVisits(ctx) {
99
108
  return visitsCitations(rest);
100
109
  case "people":
101
110
  return visitsPeople(rest);
111
+ case "who":
112
+ return visitsWho(rest);
102
113
  case "compare":
103
114
  return visitsCompare(rest);
104
115
  case "export":
@@ -119,7 +130,7 @@ export async function cmdVisits(ctx) {
119
130
  return visitsDisconnect(rest);
120
131
  default:
121
132
  throw new CliError(
122
- "Usage: visits [list|citations|people|compare|export|sites|domain|pages|health|connect|connectors|disconnect]"
133
+ "Usage: visits [list|citations|people|who|compare|export|sites|domain|pages|health|connect|connectors|disconnect]"
123
134
  );
124
135
  }
125
136
  }
@@ -311,6 +322,25 @@ async function visitsPeople(ctx) {
311
322
  return 0;
312
323
  }
313
324
 
325
+ async function visitsWho(ctx) {
326
+ const { flags, io } = ctx;
327
+ const result = await call(ctx, "visitors_get_people");
328
+ printResult(io, flags, result, (r) => {
329
+ if (!r.enabled) return "Identification is off for this site.";
330
+ const lines = [];
331
+ if (r.icp) lines.push(`ICP: ${r.icp} (${r.icp_total} fit)`);
332
+ else if (r.icp_filter !== null) lines.push("No ICP set. Set it in Memory → General.");
333
+ lines.push(`${r.total} identified in the last ${r.window_days} days`);
334
+ for (const v of r.visitors) {
335
+ const fit = v.icp_fit === true ? ` ICP: ${v.icp_reason ?? "fits"}` : "";
336
+ const where = [v.title, v.company ?? v.company_domain].filter(Boolean).join(", ");
337
+ lines.push(` ${v.name ?? "Unknown"}${where ? ` (${where})` : ""} ${v.category ?? "Others"}${fit}`);
338
+ }
339
+ return lines.join("\n");
340
+ });
341
+ return 0;
342
+ }
343
+
314
344
  async function visitsCompare(ctx) {
315
345
  const { flags, io } = ctx;
316
346
  const result = await call(ctx, "visitors_compare_agents");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.177.24",
3
+ "version": "0.177.26",
4
4
  "description": "Spin up and manage Letter phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",