@ghostystudio/cli 0.103.0 → 0.104.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/dist/index.js +16 -14
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1190,7 +1190,7 @@ async function postLong(path2, body, timeoutMs = 9e5) {
|
|
|
1190
1190
|
const req = httpsRequest(`${base}${path2}`, {
|
|
1191
1191
|
method: "POST",
|
|
1192
1192
|
timeout: timeoutMs,
|
|
1193
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
1193
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.104.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
1194
1194
|
}, (res) => {
|
|
1195
1195
|
let buf = "";
|
|
1196
1196
|
res.on("data", (c) => buf += c);
|
|
@@ -1232,7 +1232,7 @@ async function request(path2, opts = {}, retried = false) {
|
|
|
1232
1232
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
1233
1233
|
headers: {
|
|
1234
1234
|
authorization: `Bearer ${token}`,
|
|
1235
|
-
"user-agent": `ghosty-cli/${"0.
|
|
1235
|
+
"user-agent": `ghosty-cli/${"0.104.0"}`,
|
|
1236
1236
|
"accept-language": lang(),
|
|
1237
1237
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
1238
1238
|
...opts.headers
|
|
@@ -11297,7 +11297,7 @@ async function call(path2, v, init = {}) {
|
|
|
11297
11297
|
"x-ghosty-ts": ts,
|
|
11298
11298
|
"x-ghosty-sig": sig,
|
|
11299
11299
|
"content-type": "application/json",
|
|
11300
|
-
"user-agent": `ghosty-cli/${"0.
|
|
11300
|
+
"user-agent": `ghosty-cli/${"0.104.0"}`
|
|
11301
11301
|
},
|
|
11302
11302
|
body: method === "GET" ? void 0 : raw
|
|
11303
11303
|
});
|
|
@@ -13155,29 +13155,30 @@ ${t(`Cards appear on the team's board (no "new lead" alerts).`, "Las tarjetas ap
|
|
|
13155
13155
|
out({ ...sum, conversations: done }, () => `${lavender("\u2713")} ${t(`${sum.newCards} new card(s), ${sum.updatedCards} updated, ${sum.messages} message(s), ${sum.orders} order(s)`, `${sum.newCards} tarjeta(s) nueva(s), ${sum.updatedCards} actualizada(s), ${sum.messages} mensaje(s), ${sum.orders} pedido(s)`)}${files(sum)}${sum.suppressed ? dim(t(` \xB7 ${sum.suppressed} bot draft(s) the customer never saw, skipped`, ` \xB7 se omitieron ${sum.suppressed} borrador(es) del bot que el cliente nunca vio`)) : ""}${pausedLine(sum, id)}`);
|
|
13156
13156
|
}
|
|
13157
13157
|
async function contactsCmd(id, v) {
|
|
13158
|
-
if (!id || !v.integration) throw usage(t("Missing agent id or --integration.", "Falta el id del agente o --integration."), t("Example", "Ejemplo") + ": ghosty channels whatsapp contacts <agent-id> --integration <id> [--new-only on|off] [--mute PHONE] [--allow PHONE] [--unmute PHONE] [--signature \u{1F47E}|off] [--seed] [--list] [--q TEXT]");
|
|
13158
|
+
if (!id || !v.integration) throw usage(t("Missing agent id or --integration.", "Falta el id del agente o --integration."), t("Example", "Ejemplo") + ": ghosty channels whatsapp contacts <agent-id> --integration <id> [--new-only on|off] [--mute PHONE] [--allow PHONE] [--team PHONE] [--unmute PHONE] [--signature \u{1F47E}|off] [--seed] [--list] [--q TEXT]");
|
|
13159
13159
|
if (v["new-only"] !== void 0 && v["new-only"] !== "on" && v["new-only"] !== "off") throw usage(t("--new-only takes on or off.", "--new-only acepta on u off."));
|
|
13160
|
-
if ([v.mute, v.unmute, v.allow].filter((x) => x !== void 0).length > 1) throw usage(t("Use only one of --mute, --allow or --unmute.", "Usa s\xF3lo uno de --mute, --allow o --unmute."));
|
|
13160
|
+
if ([v.mute, v.unmute, v.allow, v.team].filter((x) => x !== void 0).length > 1) throw usage(t("Use only one of --mute, --allow, --team or --unmute.", "Usa s\xF3lo uno de --mute, --allow, --team o --unmute."));
|
|
13161
13161
|
const path2 = `/api/v2/agents/${enc11(id)}/whatsapp/contacts`;
|
|
13162
13162
|
if (v.list || v.q !== void 0) {
|
|
13163
13163
|
const l = await api(`${path2}?number=${enc11(v.integration)}&list=1&limit=200${v.q ? `&q=${enc11(v.q)}` : ""}`);
|
|
13164
13164
|
return out(l, () => {
|
|
13165
13165
|
if (!l.rows.length) return dim(t("No contacts yet (Meta sends the phone contacts within 24 h of connecting).", "Sin contactos todav\xEDa (Meta manda la agenda del tel\xE9fono en las primeras 24 h)."));
|
|
13166
|
-
const rule = (r2) => r2.agentOff ? t("never", "nunca") : r2.agentAlways ? t("always", "siempre") : "";
|
|
13166
|
+
const rule = (r2) => r2.agentOff ? t("never", "nunca") : r2.team ? t("team", "equipo") : r2.agentAlways ? t("always", "siempre") : "";
|
|
13167
13167
|
const lines = l.rows.map((r2) => `${r2.key.padEnd(12)} ${r2.name ?? dim(t("(no name)", "(sin nombre)"))}${rule(r2) ? ` ${lavender(rule(r2))}` : ""}`);
|
|
13168
13168
|
if (l.next != null) lines.push(dim(t(`\u2026 ${l.counts.all - l.rows.length} more; narrow it with --q`, `\u2026 ${l.counts.all - l.rows.length} m\xE1s; acota con --q`)));
|
|
13169
13169
|
return lines.join("\n");
|
|
13170
13170
|
});
|
|
13171
13171
|
}
|
|
13172
|
-
const contact = v.mute ?? v.allow ?? v.unmute;
|
|
13172
|
+
const contact = v.mute ?? v.allow ?? v.team ?? v.unmute;
|
|
13173
13173
|
const write = v["new-only"] !== void 0 || contact !== void 0 || v.seed || v.signature !== void 0;
|
|
13174
|
-
const r = write ? await api(path2, { method: "POST", body: { number: v.integration, ...v["new-only"] !== void 0 ? { newOnly: v["new-only"] === "on" } : {}, ...contact !== void 0 ? v.allow !== void 0 ? { contact, always: true } : { contact, off: !!v.mute } : {}, ...v.seed ? { seed: true } : {}, ...v.signature !== void 0 ? { signature: v.signature === "off" ? null : v.signature } : {} } }) : await api(`${path2}?number=${enc11(v.integration)}`);
|
|
13174
|
+
const r = write ? await api(path2, { method: "POST", body: { number: v.integration, ...v["new-only"] !== void 0 ? { newOnly: v["new-only"] === "on" } : {}, ...contact !== void 0 ? v.allow !== void 0 ? { contact, always: true } : v.team !== void 0 ? { contact, team: true } : { contact, off: !!v.mute } : {}, ...v.seed ? { seed: true } : {}, ...v.signature !== void 0 ? { signature: v.signature === "off" ? null : v.signature } : {} } }) : await api(`${path2}?number=${enc11(v.integration)}`);
|
|
13175
13175
|
return out(r, () => {
|
|
13176
13176
|
const lines = [
|
|
13177
13177
|
`${t("New contacts only", "S\xF3lo contactos nuevos")}: ${r.newOnly ? lavender(t("on", "encendido")) : t("off", "apagado")}${r.newSince ? dim(` (${t("since", "desde")} ${r.newSince})`) : ""}`,
|
|
13178
13178
|
`${t("Known contacts", "Contactos conocidos")}: ${r.known}${r.seededAt ? dim(` (${t("brought from Formmy", "tra\xEDdos de Formmy")} ${r.seededAt})`) : dim(t(" (still waiting for the WhatsApp history)", " (todav\xEDa esperando el historial de WhatsApp)"))}`,
|
|
13179
13179
|
`${t("Signature", "Firma")}: ${r.signature ? `${r.signature}:` : dim(t("none", "sin firma"))}`,
|
|
13180
13180
|
`${t("Always answers", "Siempre le contesta a")}: ${r.always?.length ? r.always.map((o) => o.name ? `${o.name} ${o.key}` : o.key).join(", ") : dim("\u2014")}`,
|
|
13181
|
+
`${t("Team (answers in team mode)", "Equipo (le contesta en modo equipo)")}: ${r.team?.length ? r.team.map((o) => o.name ? `${o.name} ${o.key}` : o.key).join(", ") : dim("\u2014")}`,
|
|
13181
13182
|
`${t("Never answers", "Nunca le contesta a")}: ${r.off.length ? r.off.map((o) => o.name ? `${o.name} ${o.key}` : o.key).join(", ") : dim("\u2014")}`
|
|
13182
13183
|
];
|
|
13183
13184
|
return lines.join("\n");
|
|
@@ -13878,7 +13879,7 @@ var HELPS_ES = {
|
|
|
13878
13879
|
["--cached", "groups ls: no le pide a WhatsApp la lista en vivo (m\xE1s r\xE1pido; puede faltar alg\xFAn grupo nuevo)"],
|
|
13879
13880
|
["--ads-only on|off", "link: s\xF3lo las conversaciones que vienen de un anuncio abren tarjeta (tambi\xE9n solo, para cambiarlo en un n\xFAmero ya ligado)"],
|
|
13880
13881
|
["--new-only on|off", "link: el agente s\xF3lo contesta a contactos que escriben por primera vez desde ahora; los de antes quedan en el hilo para ti (tambi\xE9n solo)"],
|
|
13881
|
-
["contacts <id> --integration ID", "s\xF3lo contactos nuevos y contactos sin agente: --new-only on|off, --mute TEL (el agente nunca le contesta a ese n\xFAmero), --allow TEL (el agente le contesta aunque sea contacto conocido), --unmute TEL (vuelve a la regla general), --signature \u{1F47E}|off (los mensajes del agente empiezan con \xAB\u{1F47E}:\xBB para que el cliente lo distinga de ti), --seed (vuelve a traer los contactos conocidos de WhatsApp), --list [--q TEXTO] (la agenda del tel\xE9fono con la regla de cada contacto; --q busca por nombre o n\xFAmero)"],
|
|
13882
|
+
["contacts <id> --integration ID", "s\xF3lo contactos nuevos y contactos sin agente: --new-only on|off, --mute TEL (el agente nunca le contesta a ese n\xFAmero), --allow TEL (el agente le contesta aunque sea contacto conocido), --team TEL (ese n\xFAmero es de tu equipo: el agente le contesta en modo equipo, sin guion de venta, sin tarjeta de lead y sin campa\xF1as), --unmute TEL (vuelve a la regla general), --signature \u{1F47E}|off (los mensajes del agente empiezan con \xAB\u{1F47E}:\xBB para que el cliente lo distinga de ti), --seed (vuelve a traer los contactos conocidos de WhatsApp), --list [--q TEXTO] (la agenda del tel\xE9fono con la regla de cada contacto; --q busca por nombre o n\xFAmero)"],
|
|
13882
13883
|
["--board NAME|agent", "link: este n\xFAmero llena su propio tablero de ventas (nombre, id o main) en vez del del agente; las tools del CRM del agente trabajan ese tablero en los turnos de este n\xFAmero. agent = vuelve al del agente. Tambi\xE9n solo, en un n\xFAmero ya ligado"],
|
|
13883
13884
|
["--list", "history --dry-run: CU\xC1LES conversaciones (tel\xE9fono, nombre, primer mensaje, mensajes, si vino de anuncio)"],
|
|
13884
13885
|
["--only-ads / --phones a,b", "history: importa (o lista) s\xF3lo las de anuncio y/o esos tel\xE9fonos"],
|
|
@@ -14805,7 +14806,7 @@ HELPS.channels = {
|
|
|
14805
14806
|
["--cached", "groups ls: don't ask WhatsApp for the live list (faster; may miss new groups)"],
|
|
14806
14807
|
["--ads-only on|off", "link: only conversations that come from an ad open a card (also alone, to change it on a linked number)"],
|
|
14807
14808
|
["--new-only on|off", "link: the agent answers only contacts writing for the first time from now on; earlier contacts stay in the thread for you (also alone)"],
|
|
14808
|
-
["contacts <id> --integration ID", "new contacts only and contacts without the agent: --new-only on|off, --mute PHONE (the agent never answers that number), --allow PHONE (the agent answers that number even if it's a known contact), --unmute PHONE (back to the general rule), --signature \u{1F47E}|off (the agent's messages start with \u201C\u{1F47E}:\u201D so customers can tell it from you), --seed (bring the known contacts from WhatsApp again), --list [--q TEXT] (the phone contacts with their rule; --q searches by name or number)"],
|
|
14809
|
+
["contacts <id> --integration ID", "new contacts only and contacts without the agent: --new-only on|off, --mute PHONE (the agent never answers that number), --allow PHONE (the agent answers that number even if it's a known contact), --team PHONE (that number is your team's: the agent answers it in team mode, with no sales script, no lead card and no campaigns), --unmute PHONE (back to the general rule), --signature \u{1F47E}|off (the agent's messages start with \u201C\u{1F47E}:\u201D so customers can tell it from you), --seed (bring the known contacts from WhatsApp again), --list [--q TEXT] (the phone contacts with their rule; --q searches by name or number)"],
|
|
14809
14810
|
["--board NAME|agent", "link: this number fills its own sales board (name, id or main) instead of the agent's; the agent's CRM tools work that board on this number's turns. agent = back to the agent's board. Also alone, on a linked number"],
|
|
14810
14811
|
["--list", "history --dry-run: WHICH conversations (phone, name, first message, messages, from an ad)"],
|
|
14811
14812
|
["--only-ads / --phones a,b", "history: import (or list) only the ones from an ad and/or those phones"],
|
|
@@ -17644,7 +17645,7 @@ ${bold("Configure an agent")}
|
|
|
17644
17645
|
channels messenger on|off <id> <page> Answer a page with this agent, or stop (off keeps logging to the board) [--take --dry-run --yes]
|
|
17645
17646
|
channels mteams ls|connect|zip|on|off|rm <id> [bot] Microsoft Teams bot (Azure Bot in the client's tenant) [--app-id --tenant --secret|GHOSTY_MTEAMS_SECRET --name --out]
|
|
17646
17647
|
channels whatsapp link|unlink <id> --integration ID --answer on|off Bring a WhatsApp Business number from Formmy/EasyBits to this agent, or send it back [--forward] [--ads-only on|off] [--new-only on|off] [--board NAME|agent] [--dry-run]
|
|
17647
|
-
channels whatsapp contacts <id> --integration ID New contacts only (the agent skips the people you already talk to) and contacts without the agent [--new-only on|off] [--mute PHONE] [--allow PHONE] [--unmute PHONE] [--signature \u{1F47E}|off] [--seed] [--list] [--q TEXT]
|
|
17648
|
+
channels whatsapp contacts <id> --integration ID New contacts only (the agent skips the people you already talk to) and contacts without the agent [--new-only on|off] [--mute PHONE] [--allow PHONE] [--team PHONE] [--unmute PHONE] [--signature \u{1F47E}|off] [--seed] [--list] [--q TEXT]
|
|
17648
17649
|
channels whatsapp history <id> --integration ID [--days 7] Bring its recent cards, messages, orders and files from Formmy (no duplicates; Formmy keeps files 7 days) [--media] [--dry-run [--list]] [--only-ads] [--phones a,b] [--column NAME]
|
|
17649
17650
|
channels wa import <id> --from easybits:ID | --from-file F | --from-dir DIR --own-number yes|no Move a personal WhatsApp session here, no QR [--dry-run] [--replace] [--no-connect]
|
|
17650
17651
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
@@ -17878,7 +17879,7 @@ ${bold("Configurar un agente")}
|
|
|
17878
17879
|
channels messenger on|off <id> <p\xE1gina> Que este agente conteste una p\xE1gina, o que deje de hacerlo (off sigue registrando en el tablero) [--take --dry-run --yes]
|
|
17879
17880
|
channels mteams ls|connect|zip|on|off|rm <id> [bot] Bot de Microsoft Teams (Azure Bot en el tenant del cliente) [--app-id --tenant --secret|GHOSTY_MTEAMS_SECRET --name --out]
|
|
17880
17881
|
channels whatsapp link|unlink <id> --integration ID --answer on|off Trae un n\xFAmero de WhatsApp Business de Formmy/EasyBits a este agente, o devu\xE9lvelo [--forward] [--ads-only on|off] [--new-only on|off] [--board NOMBRE|agent] [--dry-run]
|
|
17881
|
-
channels whatsapp contacts <id> --integration ID S\xF3lo contactos nuevos (el agente no le contesta a tu gente de siempre) y contactos sin agente [--new-only on|off] [--mute TEL] [--allow TEL] [--unmute TEL] [--signature \u{1F47E}|off] [--seed] [--list] [--q TEXT]
|
|
17882
|
+
channels whatsapp contacts <id> --integration ID S\xF3lo contactos nuevos (el agente no le contesta a tu gente de siempre) y contactos sin agente [--new-only on|off] [--mute TEL] [--allow TEL] [--team TEL] [--unmute TEL] [--signature \u{1F47E}|off] [--seed] [--list] [--q TEXT]
|
|
17882
17883
|
channels whatsapp history <id> --integration ID [--days 7] Trae de Formmy sus tarjetas, mensajes, pedidos y archivos recientes (sin duplicar; Formmy guarda los archivos 7 d\xEDas) [--media] [--dry-run [--list]] [--only-ads] [--phones a,b] [--column NOMBRE]
|
|
17883
17884
|
channels wa import <id> --from easybits:ID | --from-file F | --from-dir DIR --own-number yes|no Mueve aqu\xED una sesi\xF3n de WhatsApp personal, sin QR [--dry-run] [--replace] [--no-connect]
|
|
17884
17885
|
channels wa pair <id> --phone N Vincula un WhatsApp personal con c\xF3digo (sin QR)
|
|
@@ -18281,6 +18282,7 @@ async function main() {
|
|
|
18281
18282
|
mute: { type: "string" },
|
|
18282
18283
|
unmute: { type: "string" },
|
|
18283
18284
|
allow: { type: "string" },
|
|
18285
|
+
team: { type: "string" },
|
|
18284
18286
|
signature: { type: "string" },
|
|
18285
18287
|
seed: { type: "boolean" },
|
|
18286
18288
|
"partner-tenant": { type: "string" },
|
|
@@ -18325,7 +18327,7 @@ async function main() {
|
|
|
18325
18327
|
const tokens = splitTokens(pos, v);
|
|
18326
18328
|
globals.token = tokens.session;
|
|
18327
18329
|
globals.profile = v.profile;
|
|
18328
|
-
if (v.version) return out({ version: "0.
|
|
18330
|
+
if (v.version) return out({ version: "0.104.0" }, () => "0.104.0");
|
|
18329
18331
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
18330
18332
|
const context = (await readConfig()).workspace;
|
|
18331
18333
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -18535,7 +18537,7 @@ async function main() {
|
|
|
18535
18537
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
18536
18538
|
}
|
|
18537
18539
|
}
|
|
18538
|
-
var notice = updateNotice("0.
|
|
18540
|
+
var notice = updateNotice("0.104.0").catch(() => null);
|
|
18539
18541
|
main().then(
|
|
18540
18542
|
async () => {
|
|
18541
18543
|
const n = process.stderr.isTTY ? await notice : null;
|
package/package.json
CHANGED