@ghostystudio/cli 0.83.0 → 0.84.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/README.md CHANGED
@@ -146,6 +146,10 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
146
146
 
147
147
  Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
148
148
 
149
+ ### Changes in 0.84.0
150
+
151
+ - `coupons create|set` take `--from` (the lent plan starts then), `--redeem-by` (last moment to redeem) and `--convert-promo` (Stripe promotion code offered in /c/uso when the lent plan is about to end). New `coupons show <CODE>` (staff): who redeemed it, their plan window and who converted to a paid plan. Codes are accent- and case-insensitive.
152
+
149
153
  ### Changes in 0.83.0
150
154
 
151
155
  - `spaces plan <workspace> trial|pro|empresarial [--courtesy] [--until YYYY-MM-DD] [--note] [--dry-run]` (staff): change a workspace's plan without opening /admin/tenants, with the same rules. The dry run shows plan, model cap, tokens (used/included, hard cap or not) and «paid until» before → after. Never charges Stripe nor emails the customer; `--courtesy` records it as a no-charge courtesy in the plan note and the audit (`workspace.plan`).
package/dist/index.js CHANGED
@@ -1175,7 +1175,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
1175
1175
  const req = httpsRequest(`${base}${path}`, {
1176
1176
  method: "POST",
1177
1177
  timeout: timeoutMs,
1178
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.83.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
1178
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.84.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
1179
1179
  }, (res) => {
1180
1180
  let buf = "";
1181
1181
  res.on("data", (c) => buf += c);
@@ -1217,7 +1217,7 @@ async function request(path, opts = {}, retried = false) {
1217
1217
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
1218
1218
  headers: {
1219
1219
  authorization: `Bearer ${token}`,
1220
- "user-agent": `ghosty-cli/${"0.83.0"}`,
1220
+ "user-agent": `ghosty-cli/${"0.84.0"}`,
1221
1221
  "accept-language": lang(),
1222
1222
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
1223
1223
  ...opts.headers
@@ -11237,7 +11237,7 @@ async function call(path, v, init = {}) {
11237
11237
  "x-ghosty-ts": ts,
11238
11238
  "x-ghosty-sig": sig,
11239
11239
  "content-type": "application/json",
11240
- "user-agent": `ghosty-cli/${"0.83.0"}`
11240
+ "user-agent": `ghosty-cli/${"0.84.0"}`
11241
11241
  },
11242
11242
  body: method === "GET" ? void 0 : raw
11243
11243
  });
@@ -16281,7 +16281,10 @@ function couponRow(c) {
16281
16281
  code: c.code,
16282
16282
  credit: `$${c.creditMxn}`,
16283
16283
  plan: c.plan ?? "",
16284
+ from: c.planFrom ? c.planFrom.slice(0, 10) : "",
16284
16285
  until: c.until ? c.until.slice(0, 10) : "",
16286
+ redeem: c.redeemBy ? c.redeemBy.slice(0, 10) : "",
16287
+ promo: c.convertPromo ?? "",
16285
16288
  used: `${c.redemptions}/${c.maxRedemptions ?? "\u221E"}`,
16286
16289
  state: c.active ? t("active", "activo") : t("draft", "borrador"),
16287
16290
  only: c.eligibility ?? "",
@@ -16289,11 +16292,17 @@ function couponRow(c) {
16289
16292
  note: c.note ?? ""
16290
16293
  };
16291
16294
  }
16295
+ function redemptionRow(x) {
16296
+ return { email: x.email, redeemed: x.redeemedAt.slice(0, 10), plan: x.plan ?? "", from: x.from?.slice(0, 10) ?? "", until: x.until?.slice(0, 10) ?? "", status: x.status ?? "", converted: x.converted ?? "\u2014" };
16297
+ }
16292
16298
  function bodyOf(v) {
16293
16299
  const b = {};
16294
16300
  if (v.credit !== void 0) b.creditMxn = Number(v.credit);
16295
16301
  if (v.plan !== void 0) b.plan = v.plan === "none" ? null : v.plan;
16296
16302
  if (v.until !== void 0) b.until = v.until;
16303
+ if (v.from !== void 0) b.planFrom = v.from;
16304
+ if (v["redeem-by"] !== void 0) b.redeemBy = v["redeem-by"];
16305
+ if (v["convert-promo"] !== void 0) b.convertPromo = v["convert-promo"];
16297
16306
  if (v.max !== void 0) b.maxRedemptions = v.max === "none" ? null : Number(v.max);
16298
16307
  if (v.on) b.active = true;
16299
16308
  if (v.off) b.active = false;
@@ -16306,7 +16315,7 @@ async function couponsCmd(sub, code, v) {
16306
16315
  const one = (c) => `${lavender("\u2713")} ${c.code} $${c.creditMxn}${c.plan ? ` + ${c.plan} \u2192 ${c.until?.slice(0, 10)}` : ""} ${c.active ? t("active", "activo") : dim(t("draft", "borrador"))}`;
16307
16316
  if (!sub || sub === "ls" || sub === "list") {
16308
16317
  const r = await api("/api/v2/support/coupons");
16309
- return out(r, () => r.coupons.length ? table(r.coupons.map(couponRow), ["code", "credit", "plan", "until", "used", "state", "only", "agent", "note"]) : dim(t("No coupons.", "Sin cupones.")));
16318
+ return out(r, () => r.coupons.length ? table(r.coupons.map(couponRow), ["code", "credit", "plan", "from", "until", "redeem", "promo", "used", "state", "only", "agent", "note"]) : dim(t("No coupons.", "Sin cupones.")));
16310
16319
  }
16311
16320
  if (!code) throw usage(t("Missing the coupon code.", "Falta el c\xF3digo del cup\xF3n."), `ghosty coupons ${sub} <CODE>`);
16312
16321
  if (sub === "create") {
@@ -16317,11 +16326,17 @@ async function couponsCmd(sub, code, v) {
16317
16326
  const r = await api(`/api/v2/support/coupons/${encodeURIComponent(code)}`, { method: "PATCH", body: bodyOf(v) });
16318
16327
  return out(r, () => one(r.coupon));
16319
16328
  }
16329
+ if (sub === "show") {
16330
+ const r = await api(`/api/v2/support/coupons/${encodeURIComponent(code)}`);
16331
+ return out(r, () => `${one(r.coupon)}
16332
+ ${r.redemptions.length ? table(r.redemptions.map(redemptionRow), ["email", "redeemed", "plan", "from", "until", "status", "converted"]) : dim(t("Nobody redeemed it yet.", "Nadie lo ha canjeado."))}
16333
+ ${dim(t(`${r.converted}/${r.redemptions.length} converted to a paid plan`, `${r.converted}/${r.redemptions.length} ya pagan un plan`))}`);
16334
+ }
16320
16335
  if (sub === "redeem") {
16321
16336
  const r = await api("/api/v2/me/coupons", { method: "POST", body: { code } });
16322
16337
  return out(r, () => `${lavender("\u2713")} ${r.message}`);
16323
16338
  }
16324
- throw usage(t(`Unknown coupons subcommand: ${sub}.`, `Subcomando de coupons desconocido: ${sub}.`), "ghosty coupons ls|create|set|redeem <CODE>");
16339
+ throw usage(t(`Unknown coupons subcommand: ${sub}.`, `Subcomando de coupons desconocido: ${sub}.`), "ghosty coupons ls|create|set|show|redeem <CODE>");
16325
16340
  }
16326
16341
 
16327
16342
  // src/commands/ads.ts
@@ -16667,7 +16682,8 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
16667
16682
  staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
16668
16683
  staff assign|unassign <staff> <client> Staff sees and runs that account's agents, documents, databases and boards as themselves (no keys, billing or transfers; logged) [--reason]
16669
16684
  settings ls|set|unset <KEY> [value] Platform switches (staff): who answers /c without an account, native subagents\u2026 [+id/-id edits a list]
16670
- coupons ls|create|set <CODE> Redeemable coupons (staff): balance in cost pesos and an optional lent plan until a date; created as a draft [--credit 50] [--plan pro|power|max --until 2026-11-13] [--max 100] [--eligibility hackathon:<event>: accepted people only] [--agent ID: each account gets its own copy] [--on|--off] [--note]
16685
+ coupons ls|create|set <CODE> Redeemable coupons (staff): balance in cost pesos and an optional lent plan until a date; created as a draft [--credit 50] [--plan pro|power|max --until 2026-11-13] [--max 100] [--eligibility hackathon:<event>: accepted people only] [--agent ID: each account gets its own copy] [--from DATE: the lent plan starts then] [--redeem-by DATE: last day to redeem] [--convert-promo STRIPE_CODE: offered when the plan ends] [--on|--off] [--note]
16686
+ coupons show <CODE> Who redeemed it: plan window (pending/active/ended) and who converted to a paid plan (staff)
16671
16687
  coupons redeem <CODE> Redeem a coupon for your account (also /canjear?codigo=CODE)
16672
16688
  ads watch [ls|run] Campaign watch (staff): Meta campaigns that stop delivering and ads-only WhatsApp numbers with no leads for 24 h [run --dry-run: what it would alert]
16673
16689
  audit ls The audit log: who changed what (agent page, channels, pauses, replies, transfers, "log in as") [--workspace SLUG] [--agent ID] [--actor EMAIL] [--action A] [--since 24h] [--limit N]
@@ -16875,7 +16891,8 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
16875
16891
  staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
16876
16892
  staff assign|unassign <staff> <cliente> El staff ve y opera agentes, documentos, bases y tableros de esa cuenta como s\xED mismo (sin llaves, cobro ni traspasos; queda en bit\xE1cora) [--reason]
16877
16893
  settings ls|set|unset <CLAVE> [valor] Perillas de la plataforma (staff): qui\xE9n atiende /c sin cuenta, subagentes nativos\u2026 [+id/-id edita una lista]
16878
- coupons ls|create|set <C\xD3DIGO> Cupones canjeables (staff): saldo en pesos de costo y un plan prestado opcional hasta una fecha; nacen como borrador [--credit 50] [--plan pro|power|max --until 2026-11-13] [--max 100] [--eligibility hackathon:<evento>: s\xF3lo aceptados] [--agent ID: cada cuenta recibe su copia] [--on|--off] [--note]
16894
+ coupons ls|create|set <C\xD3DIGO> Cupones canjeables (staff): saldo en pesos de costo y un plan prestado opcional hasta una fecha; nacen como borrador [--credit 50] [--plan pro|power|max --until 2026-11-13] [--max 100] [--eligibility hackathon:<evento>: s\xF3lo aceptados] [--agent ID: cada cuenta recibe su copia] [--from FECHA: el plan prestado arranca ah\xED] [--redeem-by FECHA: \xFAltimo d\xEDa para canjear] [--convert-promo C\xD3DIGO_STRIPE: se ofrece al terminar el plan] [--on|--off] [--note]
16895
+ coupons show <C\xD3DIGO> Qui\xE9n lo canje\xF3: ventana del plan (por empezar/activo/termin\xF3) y qui\xE9n ya paga un plan (staff)
16879
16896
  coupons redeem <C\xD3DIGO> Canjea un cup\xF3n para tu cuenta (tambi\xE9n /canjear?codigo=C\xD3DIGO)
16880
16897
  ads watch [ls|run] Vig\xEDa de campa\xF1as (staff): campa\xF1as de Meta que dejan de entregar y n\xFAmeros \xABs\xF3lo anuncios\xBB sin leads en 24 h [run --dry-run: lo que avisar\xEDa]
16881
16898
  audit ls La bit\xE1cora: qui\xE9n cambi\xF3 qu\xE9 (ficha, canales, pausas, respuestas, traspasos, \xABentrar como\xBB) [--workspace SLUG] [--agent ID] [--actor CORREO] [--action A] [--since 24h] [--limit N]
@@ -17117,6 +17134,8 @@ async function main() {
17117
17134
  until: { type: "string" },
17118
17135
  credit: { type: "string" },
17119
17136
  eligibility: { type: "string" },
17137
+ "redeem-by": { type: "string" },
17138
+ "convert-promo": { type: "string" },
17120
17139
  title: { type: "string" },
17121
17140
  body: { type: "string" },
17122
17141
  profile: { type: "string" },
@@ -17362,7 +17381,7 @@ async function main() {
17362
17381
  const tokens = splitTokens(pos, v);
17363
17382
  globals.token = tokens.session;
17364
17383
  globals.profile = v.profile;
17365
- if (v.version) return out({ version: "0.83.0" }, () => "0.83.0");
17384
+ if (v.version) return out({ version: "0.84.0" }, () => "0.84.0");
17366
17385
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
17367
17386
  const context = (await readConfig()).workspace;
17368
17387
  if (!explicitToken()?.startsWith("gat_")) {
@@ -17561,7 +17580,7 @@ async function main() {
17561
17580
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
17562
17581
  }
17563
17582
  }
17564
- var notice = updateNotice("0.83.0").catch(() => null);
17583
+ var notice = updateNotice("0.84.0").catch(() => null);
17565
17584
  main().then(
17566
17585
  async () => {
17567
17586
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.83.0",
3
+ "version": "0.84.0",
4
4
  "description": "Official Ghosty Studio CLI — configure, test and chat with your agents from the terminal. Built for humans and coding agents.",
5
5
  "type": "module",
6
6
  "bin": {