@ghostystudio/cli 0.24.0 → 0.24.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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/dist/index.js +18 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -90,6 +90,11 @@ Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
90
90
  - `try --replay FILE --out DIR`: replays real conversations from your machine. The report is written after every step, survives Ghosty deploys (it honors `Retry-After`), and `--resume` continues a partial run.
91
91
  - `agents doctor` speaks English like the rest of the CLI; `channels whatsapp ls` returns a full URL.
92
92
 
93
+ ### Changes in 0.24.2
94
+
95
+ - `channels whatsapp integrations` also lists numbers the workspace already linked in gs (even if another Formmy account owns them); staff: `--email`.
96
+ - `dbs rename` and `dbs rm` also work for Ghosty staff (migrations), not only the database's owner.
97
+
93
98
  ### Changes in 0.24.0
94
99
 
95
100
  - `dbs rename <agent> <db> <new> [--dry-run]`: renames the database and rewrites every prompt, env value and SKILL.md that names it (the dry run lists them).
package/dist/index.js CHANGED
@@ -7600,6 +7600,7 @@ var SERVER_MESSAGES = [
7600
7600
  ["falta name (el nombre nuevo)", "missing name (the new name)"],
7601
7601
  ["s\xF3lo el due\xF1o, un admin del agente o staff ven los n\xFAmeros de Formmy", "only the owner, an admin of the agent or staff can see the Formmy numbers"],
7602
7602
  ["no pude leer sus turnos", "couldn't read its turns"],
7603
+ ["s\xF3lo staff lista los n\xFAmeros de otro correo", "only staff can list another email's numbers"],
7603
7604
  ["Tu plan incluye {} base{} de datos.", "Your plan includes {} database{}."],
7604
7605
  ["El nombre lleva letras min\xFAsculas, n\xFAmeros, guiones o guiones bajos (m\xE1x. 64).", "The name takes lowercase letters, numbers, hyphens or underscores (max 64)."],
7605
7606
  ["Nombre de tabla inv\xE1lido (letras, n\xFAmeros y _).", "Invalid table name (letters, numbers and _)."],
@@ -8267,7 +8268,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
8267
8268
  const req = httpsRequest(`${base}${path}`, {
8268
8269
  method: "POST",
8269
8270
  timeout: timeoutMs,
8270
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.24.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8271
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.24.2"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8271
8272
  }, (res) => {
8272
8273
  let buf = "";
8273
8274
  res.on("data", (c) => buf += c);
@@ -8309,7 +8310,7 @@ async function request(path, opts = {}, retried = false) {
8309
8310
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
8310
8311
  headers: {
8311
8312
  authorization: `Bearer ${token}`,
8312
- "user-agent": `ghosty-cli/${"0.24.0"}`,
8313
+ "user-agent": `ghosty-cli/${"0.24.2"}`,
8313
8314
  "accept-language": lang(),
8314
8315
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
8315
8316
  ...opts.headers
@@ -9304,7 +9305,7 @@ async function call(path, v, init = {}) {
9304
9305
  "x-ghosty-ts": ts,
9305
9306
  "x-ghosty-sig": sig,
9306
9307
  "content-type": "application/json",
9307
- "user-agent": `ghosty-cli/${"0.24.0"}`
9308
+ "user-agent": `ghosty-cli/${"0.24.2"}`
9308
9309
  },
9309
9310
  body: method === "GET" ? void 0 : raw
9310
9311
  });
@@ -10011,7 +10012,7 @@ async function channelsCmd(kind, sub, id, ref, v) {
10011
10012
  if (!id) throw usage(t("Missing agent id.", "Falta el id del agente."), t("Example", "Ejemplo") + ": ghosty channels whatsapp ls <agent-id>");
10012
10013
  if (sub === "link" || sub === "unlink") return linkCmd(sub, id, v);
10013
10014
  if (sub === "history") return historyCmd(id, v);
10014
- if (sub === "integrations") return integrationsCmd(id);
10015
+ if (sub === "integrations") return integrationsCmd(id, v.email);
10015
10016
  if (sub === "import" || sub === "status" || sub === "pause" || sub === "pair") return waCmd(sub, id, v);
10016
10017
  if (sub === "enable" && !v["dry-run"]) requireYesIfHeadless(v.yes, `ghosty channels whatsapp enable ${id} ${ref ?? "<number>"}`);
10017
10018
  const path = `/api/v2/agents/${enc7(id)}/whatsapp`;
@@ -10150,8 +10151,8 @@ function bareMediaFlag(argv) {
10150
10151
  if (argv[0] !== "channels" || !argv.includes("history")) return argv;
10151
10152
  return argv.map((a, i) => a === "--media" && (argv[i + 1] === void 0 || argv[i + 1].startsWith("-")) ? "--media=" : a);
10152
10153
  }
10153
- async function integrationsCmd(id) {
10154
- const r = await api(`/api/v2/agents/${enc7(id)}/whatsapp/integrations`);
10154
+ async function integrationsCmd(id, email) {
10155
+ const r = await api(`/api/v2/agents/${enc7(id)}/whatsapp/integrations${email ? `?email=${enc7(email)}` : ""}`);
10155
10156
  const who2 = { gs: "gs", easybits: "EasyBits", droplet: "droplet", formmy: "Formmy", other: t("other", "otro") };
10156
10157
  const rows = r.integrations.map((i) => ({
10157
10158
  number: i.phoneNumber ? `+${i.phoneNumber}` : dim("?"),
@@ -10164,7 +10165,7 @@ async function integrationsCmd(id) {
10164
10165
  return out(
10165
10166
  r,
10166
10167
  () => rows.length ? `${table(rows, ["number", "name", "answered by", "formmy forwards", "formmy agent", "integration"])}
10167
- ${dim(`${t("Next", "Siguiente")}: ghosty channels whatsapp link ${id} --integration <integration> --answer on|off --dry-run`)}` : dim(t(`${r.ownerEmail} has no WhatsApp Business numbers in Formmy.`, `${r.ownerEmail} no tiene n\xFAmeros de WhatsApp Business en Formmy.`))
10168
+ ${dim(`${t("Next", "Siguiente")}: ghosty channels whatsapp link ${id} --integration <integration> --answer on|off --dry-run`)}` : dim(t(`${r.ownerEmail} has no WhatsApp Business numbers in Formmy (staff: --email <other Formmy account>).`, `${r.ownerEmail} no tiene n\xFAmeros de WhatsApp Business en Formmy (staff: --email <otra cuenta de Formmy>).`))
10168
10169
  );
10169
10170
  }
10170
10171
  async function historyCmd(id, v) {
@@ -10417,7 +10418,7 @@ var HELPS_ES = {
10417
10418
  "<db> es el id de la base o su nombre. Desde canales del due\xF1o el agente lee y escribe todo lo concedido.",
10418
10419
  "tables dice, por columna de fotos/ligas, cu\xE1ntas son permanentes (img.ghosty.studio), de fuera o vac\xEDas; import avisa antes de reemplazar ligas permanentes por ligas de fuera.",
10419
10420
  "import con replace avisa de las filas escritas en gs que EasyBits no tiene (una base compartida con agentes que ya corren en gs) y pregunta antes de borrarlas.",
10420
- "rename tambi\xE9n reescribe cada prompt, valor de env y SKILL.md que nombra la base; un prompt derivado sigue a su base. rm borra la base misma (revoke s\xF3lo le quita el acceso a este agente); las dos son s\xF3lo del due\xF1o."
10421
+ "rename tambi\xE9n reescribe cada prompt, valor de env y SKILL.md que nombra la base; un prompt derivado sigue a su base. rm borra la base misma (revoke s\xF3lo le quita el acceso a este agente); las dos son s\xF3lo del due\xF1o (o del staff de Ghosty)."
10421
10422
  ]
10422
10423
  },
10423
10424
  turns: {
@@ -10485,6 +10486,7 @@ var HELPS_ES = {
10485
10486
  ["--role R", "groups: equipo (el equipo: escribe en bases de datos, tools de admin) o cliente (como cualquier cliente)"],
10486
10487
  ["--cached", "groups ls: no le pide a WhatsApp la lista en vivo (m\xE1s r\xE1pido; puede faltar alg\xFAn grupo nuevo)"],
10487
10488
  ["--integration ID", "link/unlink/history: el id de la Integration del n\xFAmero de WhatsApp Business en Formmy"],
10489
+ ["--email E", "integrations (staff): lista los n\xFAmeros de otra cuenta de Formmy"],
10488
10490
  ["--days N", "history: conversaciones activas en los \xFAltimos N d\xEDas (1-30, default 7)"],
10489
10491
  ["--media", "history: s\xF3lo re-copia los archivos que faltan (fotos, PDF, audios) de las conversaciones ya importadas"],
10490
10492
  ["--answer on|off", "link (obligatorio, sin default): on = este agente contesta a clientes reales; off = s\xF3lo registra"],
@@ -10500,7 +10502,7 @@ var HELPS_ES = {
10500
10502
  "Apagarlo sigue registrando los mensajes; nadie los contesta.",
10501
10503
  "Los grupos son del WhatsApp PERSONAL emparejado al agente (no de WhatsApp Business). <group> es su nombre o su jid.",
10502
10504
  "link mueve un n\xFAmero que ya vive en Formmy (EasyBits, un droplet) sin rehacer el alta de Meta; unlink lo regresa. S\xF3lo el due\xF1o, un admin del agente o el staff de Ghosty.",
10503
- "integrations lista los n\xFAmeros de WhatsApp Business del due\xF1o en Formmy (n\xFAmero, nombre, qui\xE9n contesta hoy: gs, EasyBits, un droplet o Formmy) con el id de la Integration que piden link e history.",
10505
+ "integrations lista los n\xFAmeros de WhatsApp Business del due\xF1o en Formmy (n\xFAmero, nombre, qui\xE9n contesta hoy: gs, EasyBits, un droplet o Formmy) con el id de la Integration que piden link e history. Tambi\xE9n salen los n\xFAmeros que el espacio ya enlaz\xF3 en gs, aunque en Formmy sean de otra cuenta.",
10504
10506
  "history trae al tablero las tarjetas, mensajes y pedidos recientes del n\xFAmero desde Formmy (enl\xE1zalo antes; --dry-run funciona sin enlazar, para decidir --days). Repetirlo nunca duplica: c\xF3rrelo antes del corte y otra vez justo en el corte. Los archivos (fotos, PDF, audios) tambi\xE9n se copian a gs: Formmy los borra a los 7 d\xEDas, as\xED que trae el n\xFAmero dentro de esa semana; una copia que fall\xF3 se reintenta con --media.",
10505
10507
  "import: apaga primero el socket de EasyBits SIN logout (dos sockets se tumban entre s\xED; un logout invalida las llaves). Borra el archivo despu\xE9s."
10506
10508
  ]
@@ -10754,7 +10756,7 @@ var HELPS = {
10754
10756
  "<db> is the database id or its name. From owner channels the agent reads and writes everything granted.",
10755
10757
  "tables shows, per photo/link column, how many links are permanent (img.ghosty.studio), external or empty; import warns before replacing permanent links with external ones.",
10756
10758
  "import with replace warns about rows written in gs that EasyBits doesn't have (a database shared with agents already running in gs) and asks before deleting them.",
10757
- "rename also rewrites every prompt, env value and SKILL.md that names the database; a derived prompt follows its base. rm deletes the database itself (revoke only removes this agent's access); only its owner can do either."
10759
+ "rename also rewrites every prompt, env value and SKILL.md that names the database; a derived prompt follows its base. rm deletes the database itself (revoke only removes this agent's access); only its owner (or Ghosty staff) can do either."
10758
10760
  ],
10759
10761
  learn: `${REF}#bases-de-datos`
10760
10762
  },
@@ -10860,7 +10862,7 @@ HELPS.channels = {
10860
10862
  "ghosty channels whatsapp ls <agent-id>",
10861
10863
  "ghosty channels whatsapp enable <agent-id> <number> [--dry-run] [--yes]",
10862
10864
  "ghosty channels whatsapp disable <agent-id> <number> [--dry-run]",
10863
- "ghosty channels whatsapp integrations <agent-id>",
10865
+ "ghosty channels whatsapp integrations <agent-id> [--email OTHER]",
10864
10866
  "ghosty channels whatsapp link <agent-id> --integration <formmy-id> --answer on|off [--forward] [--dry-run] [--yes]",
10865
10867
  "ghosty channels whatsapp unlink <agent-id> --integration <formmy-id> [--dry-run] [--yes]",
10866
10868
  "ghosty channels whatsapp history <agent-id> --integration <formmy-id> [--days 7] [--media] [--dry-run] [--yes]",
@@ -10878,6 +10880,7 @@ HELPS.channels = {
10878
10880
  ["--role R", "groups: equipo (the team: writes to databases, admin tools) or cliente (like any customer)"],
10879
10881
  ["--cached", "groups ls: don't ask WhatsApp for the live list (faster; may miss new groups)"],
10880
10882
  ["--integration ID", "link/unlink/history: the WhatsApp Business number's Integration id in Formmy"],
10883
+ ["--email E", "integrations (staff): list the numbers of another Formmy account"],
10881
10884
  ["--days N", "history: conversations active in the last N days (1-30, default 7)"],
10882
10885
  ["--media", "history: only re-copy the missing files (photos, PDFs, audio) of conversations already imported"],
10883
10886
  ["--answer on|off", "link (required, no default): on = this agent answers real customers; off = it only records"],
@@ -10905,7 +10908,7 @@ HELPS.channels = {
10905
10908
  "Disabling keeps logging messages; nobody answers them.",
10906
10909
  "Groups belong to the PERSONAL WhatsApp paired to the agent (not WhatsApp Business). <group> is its name or its jid.",
10907
10910
  "link moves a number that already lives in Formmy (EasyBits, a droplet) without redoing Meta's signup; unlink sends it back. Only the owner, an admin of the agent or Ghosty staff.",
10908
- "integrations lists the owner's WhatsApp Business numbers in Formmy (number, name, who answers today: gs, EasyBits, a droplet or Formmy) with the Integration id that link and history take.",
10911
+ "integrations lists the owner's WhatsApp Business numbers in Formmy (number, name, who answers today: gs, EasyBits, a droplet or Formmy) with the Integration id that link and history take. Numbers the workspace already linked in gs show up too, even if another Formmy account owns them.",
10909
10912
  "history brings the number's recent cards, messages and orders from Formmy to the board (link it first; --dry-run works before linking, to choose --days). Re-running never duplicates: run it before the cutover and again right at it. Files (photos, PDFs, audio) are copied to gs too: Formmy deletes them after 7 days, so bring the number within that week; a copy that failed is retried with --media.",
10910
10913
  "import: turn off the EasyBits socket first WITHOUT logout (two sockets knock each other off; a logout invalidates the keys). Delete the file afterwards."
10911
10914
  ],
@@ -11694,6 +11697,7 @@ async function main() {
11694
11697
  "unset-env": { type: "string" },
11695
11698
  orphans: { type: "boolean" },
11696
11699
  skipped: { type: "boolean" },
11700
+ email: { type: "string" },
11697
11701
  keep: { type: "boolean" },
11698
11702
  boxes: { type: "boolean" },
11699
11703
  like: { type: "string" },
@@ -11755,7 +11759,7 @@ async function main() {
11755
11759
  const tokens = splitTokens(pos, v);
11756
11760
  globals.token = tokens.session;
11757
11761
  globals.profile = v.profile;
11758
- if (v.version) return out({ version: "0.24.0" }, () => "0.24.0");
11762
+ if (v.version) return out({ version: "0.24.2" }, () => "0.24.2");
11759
11763
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
11760
11764
  const context = (await readConfig()).workspace;
11761
11765
  if (!explicitToken()?.startsWith("gat_")) {
@@ -11874,7 +11878,7 @@ async function main() {
11874
11878
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
11875
11879
  }
11876
11880
  }
11877
- var notice = updateNotice("0.24.0").catch(() => null);
11881
+ var notice = updateNotice("0.24.2").catch(() => null);
11878
11882
  main().then(
11879
11883
  async () => {
11880
11884
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.24.0",
3
+ "version": "0.24.2",
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": {