@ghostystudio/cli 0.36.0 → 0.37.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
@@ -143,6 +143,7 @@ Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
143
143
  - `partner credentials create|rotate --env-file PATH` (mode 600, nothing printed) or `--format env` (pipe to `fly secrets import`). The secret's env var is now `GHOSTY_PARTNER_KEY_SECRET` (`GHOSTY_PARTNER_SECRET` still works).
144
144
  - `partner agent apply --prompt-file prompt.md`; `partner try --verbose` prints each tool's arguments and milliseconds.
145
145
  - `partner agent get|apply --agent SLUG` and `partner try --agent SLUG`: several agents per partner (e.g. `nik-admin`, `nik-public`). `channels whatsapp link … --partner-tenant <externalId> --partner-agent <slug>`: a business's WhatsApp Business number answered by that partner agent.
146
+ - `partner waba links ls|create|set|rm`: a business's WhatsApp Business number in Formmy pointed at a partner agent (url + secret, no partner keys).
146
147
  - `partner wa groups ls|create|link|unlink`: WhatsApp groups of a partner agent's own number (e.g. `nik-admin`), each linked to a business.
147
148
  - Empty `partner ls|credentials ls|tenants ls` say what to do next. `login --device --profile <client>` explains how to sign in a client's account (they approve the link).
148
149
 
package/dist/index.js CHANGED
@@ -8379,7 +8379,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
8379
8379
  const req = httpsRequest(`${base}${path}`, {
8380
8380
  method: "POST",
8381
8381
  timeout: timeoutMs,
8382
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.36.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8382
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.37.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8383
8383
  }, (res) => {
8384
8384
  let buf = "";
8385
8385
  res.on("data", (c) => buf += c);
@@ -8421,7 +8421,7 @@ async function request(path, opts = {}, retried = false) {
8421
8421
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
8422
8422
  headers: {
8423
8423
  authorization: `Bearer ${token}`,
8424
- "user-agent": `ghosty-cli/${"0.36.0"}`,
8424
+ "user-agent": `ghosty-cli/${"0.37.0"}`,
8425
8425
  "accept-language": lang(),
8426
8426
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
8427
8427
  ...opts.headers
@@ -9523,6 +9523,12 @@ ${bold("WhatsApp groups")} ${dim("(the number of a partner agent, e.g. nik-admi
9523
9523
  partner wa groups link <jid> --tenant ID --agent SLUG [--off] Link a group the number is already in
9524
9524
  partner wa groups unlink <jid> [--agent SLUG] Unlink and turn off (the number stays in the group)
9525
9525
 
9526
+ ${bold("WhatsApp Business")} ${dim("(a business's number in Formmy, answered by a partner agent, e.g. nik-public)")}
9527
+ partner waba links ls [--tenant ID] Numbers, business, agent, on/off
9528
+ partner waba links create --tenant ID --agent SLUG New link (off): prints url + secret for Formmy, ONCE
9529
+ partner waba links set <id> [--integration ID] [--phone N] [--name N] [--on|--off] What Formmy returned; turn on/off
9530
+ partner waba links rm <id> Turn off (history stays)
9531
+
9526
9532
  ${bold("Try it")}
9527
9533
  partner try <externalId> "message" One turn [--agent SLUG] [--group END_USER_ID] [--turn-token SHORT_LIVED_TOKEN] [--verbose: tool args and ms]
9528
9534
  (the turn token goes to YOUR MCP as \${turn.token}; --token also works here)
@@ -9562,6 +9568,12 @@ ${bold("Grupos de WhatsApp")} ${dim("(el n\xFAmero de un agente de partner, p.
9562
9568
  partner wa groups link <jid> --tenant ID --agent SLUG [--off] Liga un grupo donde ya est\xE1 el n\xFAmero
9563
9569
  partner wa groups unlink <jid> [--agent SLUG] Lo desliga y lo apaga (el n\xFAmero sigue en el grupo)
9564
9570
 
9571
+ ${bold("WhatsApp Business")} ${dim("(el n\xFAmero de un negocio en Formmy, atendido por un agente de partner, p. ej. nik-public)")}
9572
+ partner waba links ls [--tenant ID] N\xFAmeros, negocio, agente, prendido/apagado
9573
+ partner waba links create --tenant ID --agent SLUG Link nuevo (apagado): imprime url + secreto para Formmy, UNA vez
9574
+ partner waba links set <id> [--integration ID] [--phone N] [--name N] [--on|--off] Lo que devolvi\xF3 Formmy; prender/apagar
9575
+ partner waba links rm <id> Apagar (el historial queda)
9576
+
9565
9577
  ${bold("Pru\xE9balo")}
9566
9578
  partner try <externalId> "mensaje" Un turno [--agent SLUG] [--group END_USER_ID] [--turn-token TOKEN_DE_VIDA_CORTA] [--verbose: args y ms de cada tool]
9567
9579
  (el token del turno llega a TU MCP como \${turn.token}; --token tambi\xE9n sirve aqu\xED)
@@ -9595,7 +9607,7 @@ async function call(path, v, init = {}) {
9595
9607
  "x-ghosty-ts": ts,
9596
9608
  "x-ghosty-sig": sig,
9597
9609
  "content-type": "application/json",
9598
- "user-agent": `ghosty-cli/${"0.36.0"}`
9610
+ "user-agent": `ghosty-cli/${"0.37.0"}`
9599
9611
  },
9600
9612
  body: method === "GET" ? void 0 : raw
9601
9613
  });
@@ -9774,6 +9786,43 @@ ${t("Invite", "Invitaci\xF3n")}: ${r.inviteUrl}`);
9774
9786
  }
9775
9787
  throw usage(t(`Unknown wa groups subcommand: ${sub}.`, `Subcomando de wa groups desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty partner wa groups ls | create | link | unlink");
9776
9788
  }
9789
+ async function wabaCmd(what, sub, id, v) {
9790
+ if (what !== "links") throw usage(t("Try: ghosty partner waba links ls", "Prueba: ghosty partner waba links ls"));
9791
+ const base = "/api/v2/partner/waba/links";
9792
+ const row = (l) => ({ id: l.id, business: l.externalId, agent: l.agent ?? "app", number: l.phoneNumber ? `+${l.phoneNumber}` : dim("\u2014"), integration: l.integrationId ?? dim("\u2014"), status: l.enabled ? lavender("on") : dim("off") });
9793
+ const cols = ["id", "business", "agent", "number", "integration", "status"];
9794
+ if (!sub || sub === "ls" || sub === "list") {
9795
+ const r = await json(`${base}${v.tenant ? `?externalId=${enc5(v.tenant)}` : ""}`, v);
9796
+ return out(r, () => r.links.length ? table(r.links.map(row), cols) : dim(t("No links. Create one: ghosty partner waba links create --tenant <id> --agent nik-public", "Sin links. Crea uno: ghosty partner waba links create --tenant <id> --agent nik-public")));
9797
+ }
9798
+ if (sub === "create") {
9799
+ if (!v.tenant || !v.agent) throw usage(t("Missing --tenant or --agent.", "Falta --tenant o --agent."), `${t("Example", "Ejemplo")}: ghosty partner waba links create --tenant org_123 --agent nik-public`);
9800
+ const r = await json(base, v, { method: "POST", body: { externalId: v.tenant, agent: v.agent } });
9801
+ return out(
9802
+ r,
9803
+ () => [
9804
+ `${lavender("\u2713")} ${t("Link created (off)", "Link creado (apagado)")}: ${r.id}`,
9805
+ `url: ${r.url}`,
9806
+ `secret: ${r.secret}`,
9807
+ dim(t("Give both to Formmy (externalAgentUrl / externalAgentSecret). The secret is not shown again.", "Dale los dos a Formmy (externalAgentUrl / externalAgentSecret). El secreto no se vuelve a ense\xF1ar.")),
9808
+ dim(`${t("Then", "Despu\xE9s")}: ghosty partner waba links set ${r.id} --integration <formmy-id> --on`)
9809
+ ].join("\n")
9810
+ );
9811
+ }
9812
+ if (!id) throw usage(t("Missing the link id.", "Falta el id del link."), `${t("See them", "Velos")}: ghosty partner waba links ls`);
9813
+ if (sub === "set") {
9814
+ if (v.on && v.off) throw usage(t("--on or --off, not both.", "--on o --off, no los dos."));
9815
+ const body = { ...v.integration ? { integrationId: v.integration } : {}, ...v.phone ? { phoneNumber: v.phone } : {}, ...v.name ? { displayName: v.name } : {}, ...v.on ? { enabled: true } : v.off ? { enabled: false } : {} };
9816
+ if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), "--integration ID --phone N --name N --on|--off");
9817
+ const r = await json(`${base}/${enc5(id)}`, v, { method: "PUT", body });
9818
+ return out(r, () => table([row(r.link)], cols));
9819
+ }
9820
+ if (sub === "rm" || sub === "off") {
9821
+ const r = await json(`${base}/${enc5(id)}`, v, { method: "DELETE" });
9822
+ return out(r, () => `${lavender("\u2713")} ${t("Off: it records and doesn't answer.", "Apagado: registra y no contesta.")}`);
9823
+ }
9824
+ throw usage(t(`Unknown waba links subcommand: ${sub}.`, `Subcomando de waba links desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty partner waba links ls | create | set | rm");
9825
+ }
9777
9826
  async function partnerCmd(sub, a1, a2, v, a3) {
9778
9827
  switch (sub) {
9779
9828
  case void 0:
@@ -9804,6 +9853,8 @@ async function partnerCmd(sub, a1, a2, v, a3) {
9804
9853
  return tryCmd(a1, a2, v);
9805
9854
  case "wa":
9806
9855
  return waCmd(a1, a2, a3, v);
9856
+ case "waba":
9857
+ return wabaCmd(a1, a2, a3, v);
9807
9858
  default:
9808
9859
  throw usage(t(`Unknown partner subcommand: ${sub}.`, `Subcomando de partner desconocido: ${sub}.`), t("Run", "Corre") + ": ghosty partner --help");
9809
9860
  }
@@ -13188,7 +13239,7 @@ async function main() {
13188
13239
  const tokens = splitTokens(pos, v);
13189
13240
  globals.token = tokens.session;
13190
13241
  globals.profile = v.profile;
13191
- if (v.version) return out({ version: "0.36.0" }, () => "0.36.0");
13242
+ if (v.version) return out({ version: "0.37.0" }, () => "0.37.0");
13192
13243
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
13193
13244
  const context = (await readConfig()).workspace;
13194
13245
  if (!explicitToken()?.startsWith("gat_")) {
@@ -13337,7 +13388,7 @@ async function main() {
13337
13388
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
13338
13389
  }
13339
13390
  }
13340
- var notice = updateNotice("0.36.0").catch(() => null);
13391
+ var notice = updateNotice("0.37.0").catch(() => null);
13341
13392
  main().then(
13342
13393
  async () => {
13343
13394
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.36.0",
3
+ "version": "0.37.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": {