@ghostystudio/cli 0.86.0 → 0.87.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 +2 -0
- package/dist/index.js +102 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,6 +74,8 @@ ghosty channels whatsapp ls|enable|disable <id> [number] [--dry-run]
|
|
|
74
74
|
ghosty channels whatsapp link|unlink <id> --integration ID --answer on|off [--forward] [--dry-run] # bring a WABA number from Formmy
|
|
75
75
|
ghosty channels whatsapp history <id> --integration ID [--days 7] [--dry-run] # its recent cards, messages and orders (no duplicates)
|
|
76
76
|
ghosty channels whatsapp|messenger connect <id> # opens Channels to connect with Meta (browser sign-in)
|
|
77
|
+
ghosty channels messenger status <id> # each page: who answers, last webhook, token health
|
|
78
|
+
ghosty channels messenger on|off <id> <page> [--take] # this agent answers the page, or stops (off keeps logging)
|
|
77
79
|
ghosty channels mteams connect <id> --app-id <guid> --tenant <guid> # Microsoft Teams bot (secret in GHOSTY_MTEAMS_SECRET); ls shows endpoint and last problem
|
|
78
80
|
ghosty channels wa import <id> --from-file F | --from-dir DIR --own-number yes|no [--dry-run] # personal WhatsApp session, no QR
|
|
79
81
|
ghosty channels wa pair|status|pause <id> [--phone N]
|
package/dist/index.js
CHANGED
|
@@ -1175,7 +1175,7 @@ async function postLong(path2, body, timeoutMs = 9e5) {
|
|
|
1175
1175
|
const req = httpsRequest(`${base}${path2}`, {
|
|
1176
1176
|
method: "POST",
|
|
1177
1177
|
timeout: timeoutMs,
|
|
1178
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
1178
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.87.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(path2, 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.
|
|
1220
|
+
"user-agent": `ghosty-cli/${"0.87.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(path2, 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.
|
|
11240
|
+
"user-agent": `ghosty-cli/${"0.87.0"}`
|
|
11241
11241
|
},
|
|
11242
11242
|
body: method === "GET" ? void 0 : raw
|
|
11243
11243
|
});
|
|
@@ -12579,7 +12579,9 @@ async function channelsCmd(kind, sub, id, ref, v) {
|
|
|
12579
12579
|
}
|
|
12580
12580
|
if (kind === "messenger" || kind === "fb") {
|
|
12581
12581
|
if (!id) throw usage(t("Missing agent id.", "Falta el id del agente."), t("Example", "Ejemplo") + ": ghosty channels messenger ls <agent-id> [--orphans]");
|
|
12582
|
-
if (sub
|
|
12582
|
+
if (sub === "status") return messengerStatusCmd(id);
|
|
12583
|
+
if (sub === "on" || sub === "off") return messengerToggleCmd(id, ref, sub === "on", v);
|
|
12584
|
+
if (sub && sub !== "ls" && sub !== "list") throw usage(t(`Unknown subcommand: ${sub}.`, `Subcomando desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty channels messenger ls|status|on|off <agent-id> [page]");
|
|
12583
12585
|
return linksCmd(id, "messenger", v.orphans);
|
|
12584
12586
|
}
|
|
12585
12587
|
if (kind !== "whatsapp" && kind !== "wa") throw usage(t(`Unknown channel: ${kind ?? "(none)"}.`, `Canal desconocido: ${kind ?? "(ninguno)"}.`), t("Try", "Prueba") + ": ghosty channels whatsapp ls <agent-id>");
|
|
@@ -12821,6 +12823,41 @@ async function pageWithRetry(fetchPage, where, waitMs = (n) => 5e3 * n, tries =
|
|
|
12821
12823
|
}
|
|
12822
12824
|
}
|
|
12823
12825
|
var lastCell = (l) => l ? `${l.agentName ?? l.agentId} ${dim(l.at.slice(0, 16).replace("T", " "))}` : dim("\u2014");
|
|
12826
|
+
function findPage(pages, ref) {
|
|
12827
|
+
const hit = pages.find((p) => p.pageId === ref) ?? pages.find((p) => (p.name ?? "").toLowerCase() === ref.toLowerCase());
|
|
12828
|
+
if (!hit) throw usage(t(`No Messenger page "${ref}" for this agent.`, `Este agente no tiene la p\xE1gina de Messenger "${ref}".`), pages.length ? `${t("Available", "Disponibles")}: ${pages.map((p) => p.name ?? p.pageId).join(", ")}` : t("Connect one first in the web (the agent's Channels page).", "Primero conecta una en la web (p\xE1gina Canales del agente)."));
|
|
12829
|
+
return hit;
|
|
12830
|
+
}
|
|
12831
|
+
var ago = (iso) => {
|
|
12832
|
+
if (!iso) return dim(t("never", "nunca"));
|
|
12833
|
+
const h = (Date.now() - new Date(iso).getTime()) / 36e5;
|
|
12834
|
+
return h < 1 ? t("< 1 h ago", "hace < 1 h") : h < 48 ? t(`${Math.round(h)} h ago`, `hace ${Math.round(h)} h`) : t(`${Math.round(h / 24)} d ago`, `hace ${Math.round(h / 24)} d`);
|
|
12835
|
+
};
|
|
12836
|
+
async function messengerStatusCmd(id) {
|
|
12837
|
+
const r = await api(`/api/v2/agents/${enc11(id)}/messenger?health=1`);
|
|
12838
|
+
const health = (p) => !p.health ? dim("?") : p.health.ok ? p.health.subscribed ? t("ok", "ok") : lavender(t("not subscribed: reconnect it", "sin suscripci\xF3n: recon\xE9ctala")) : lavender(p.health.code === 190 ? t("token dead: reconnect it", "token muerto: recon\xE9ctala") : p.health.message);
|
|
12839
|
+
const rows = r.pages.map((p) => ({
|
|
12840
|
+
page: p.name ?? p.pageId,
|
|
12841
|
+
answers: p.answers === "this" ? lavender(t("this agent", "este agente")) : p.answers === "other" ? t("another agent", "otro agente") : dim(t("nobody (records only)", "nadie (s\xF3lo registra)")),
|
|
12842
|
+
"last webhook": ago(p.lastWebhookAt),
|
|
12843
|
+
health: health(p),
|
|
12844
|
+
id: p.pageId
|
|
12845
|
+
}));
|
|
12846
|
+
return out(r, () => rows.length ? table(rows, ["page", "answers", "last webhook", "health", "id"]) : dim(t("No Messenger pages yet. Connect one in the agent's Channels page.", "Todav\xEDa no hay p\xE1ginas de Messenger. Conecta una en la p\xE1gina Canales del agente.")));
|
|
12847
|
+
}
|
|
12848
|
+
async function messengerToggleCmd(id, ref, on, v) {
|
|
12849
|
+
if (!ref) throw usage(t("Missing the page (id or name).", "Falta la p\xE1gina (id o nombre)."), t("Example", "Ejemplo") + `: ghosty channels messenger ${on ? "on" : "off"} ${id} <page-id>`);
|
|
12850
|
+
const cur = await api(`/api/v2/agents/${enc11(id)}/messenger`);
|
|
12851
|
+
const page = findPage(cur.pages, ref);
|
|
12852
|
+
const label = page.name ?? page.pageId;
|
|
12853
|
+
const plan = on ? page.answers === "other" && !v.take ? null : t(`This agent will answer the Messenger and comments of "${label}" (real customers).`, `Este agente va a contestar el Messenger y los comentarios de \xAB${label}\xBB (clientes reales).`) : t(`Nobody will answer "${label}"; messages keep landing on the board.`, `Nadie va a contestar \xAB${label}\xBB; los mensajes se siguen registrando en el tablero.`);
|
|
12854
|
+
if (!plan) throw usage(t(`Another agent answers "${label}".`, `Otro agente contesta \xAB${label}\xBB.`), t("Add --take to move it to this agent.", "Agrega --take para pasarla a este agente."));
|
|
12855
|
+
if (v["dry-run"]) return out({ dryRun: true, pageId: page.pageId, on }, () => `${plan}
|
|
12856
|
+
${dim(t("(dry run: nothing changed)", "(dry run: no se cambi\xF3 nada)"))}`);
|
|
12857
|
+
if (on) await confirm(`${plan} ${t("Continue?", "\xBFSeguir?")}`, { yes: v.yes, retry: `ghosty channels messenger on ${id} ${page.pageId}${v.take ? " --take" : ""}` });
|
|
12858
|
+
const r = await api(`/api/v2/agents/${enc11(id)}/messenger`, { method: "POST", body: { pageId: page.pageId, on, ...v.take ? { take: true } : {} } });
|
|
12859
|
+
return out(r, () => on ? t(`Now answering "${label}".`, `Ya contesta \xAB${label}\xBB.`) : t(`No longer answering "${label}"; messages are still logged.`, `Ya no contesta \xAB${label}\xBB; los mensajes se siguen registrando.`));
|
|
12860
|
+
}
|
|
12824
12861
|
async function linksCmd(id, kind, orphans) {
|
|
12825
12862
|
const r = await api(`/api/v2/agents/${enc11(id)}/channels/links?kind=${kind}${orphans ? "&orphans=1" : ""}`);
|
|
12826
12863
|
const now = (l) => l.answersNow ? l.answersNow.agentName ?? l.answersNow.agentId : l.recordsOnly ? t("nobody (records only)", "nadie (s\xF3lo registra)") : l.via === "easybits" ? "EasyBits" : l.via === "partner" ? "partner" : lavender(t("nobody", "nadie"));
|
|
@@ -13074,11 +13111,13 @@ init_api();
|
|
|
13074
13111
|
init_util();
|
|
13075
13112
|
init_i18n();
|
|
13076
13113
|
var enc12 = encodeURIComponent;
|
|
13077
|
-
|
|
13114
|
+
var FOLLOWUP_ACTIONS = /* @__PURE__ */ new Set(["on", "off", "template", "dry-run"]);
|
|
13115
|
+
async function boardsCmd(sub, a1, a2, v, context, a3) {
|
|
13078
13116
|
if (context && sub !== "assign") {
|
|
13079
13117
|
if ((sub === "ls" || sub === "list" || !sub || sub === "move-cards") && !a1) a1 = context;
|
|
13080
13118
|
else if ((sub === "create" || sub === "rm") && a1 && !a2) [a1, a2] = [context, a1];
|
|
13081
13119
|
else if (sub === "access" && !a2) [a1, a2] = [context, a1 ?? "main"];
|
|
13120
|
+
else if (sub === "followups" && (!a1 || FOLLOWUP_ACTIONS.has(a1))) [a1, a2, a3] = [context, void 0, a1];
|
|
13082
13121
|
}
|
|
13083
13122
|
switch (sub ?? "ls") {
|
|
13084
13123
|
case "ls":
|
|
@@ -13145,8 +13184,37 @@ ${table(r.people.map((p) => ({ email: p.email, until: fmtUntil(p.until) })), ["e
|
|
|
13145
13184
|
return [head + people, ...changes].join("\n");
|
|
13146
13185
|
});
|
|
13147
13186
|
}
|
|
13187
|
+
// Seguimiento de cotizaciones del tablero: estado, prender/apagar, plantilla y prueba sin enviar.
|
|
13188
|
+
case "followups": {
|
|
13189
|
+
if (!a1) throw usage(t("Missing workspace.", "Falta el espacio."), t("Example", "Ejemplo") + ": ghosty boards followups <workspace> [board|main] [on|off|template|dry-run]");
|
|
13190
|
+
if (a2 && FOLLOWUP_ACTIONS.has(a2) && !a3) [a2, a3] = [void 0, a2];
|
|
13191
|
+
const board = a2 ?? "main";
|
|
13192
|
+
const path2 = `/api/v2/workspaces/${enc12(a1)}/boards/followups`;
|
|
13193
|
+
const steps = v.steps ? v.steps.split(",").map((x) => Number(x.trim())).filter((n) => n > 0) : void 0;
|
|
13194
|
+
const minutes = v.minutes === void 0 ? void 0 : v.minutes === "on";
|
|
13195
|
+
if (a3 === "dry-run") {
|
|
13196
|
+
const r2 = await api(path2, { method: "POST", body: { board, intent: "dry-run" } });
|
|
13197
|
+
return out(r2, () => r2.items.length ? table(r2.items.map((i) => ({ folio: i.folio, toque: i.step + 1, action: i.action, detail: i.detail })), ["folio", "toque", "action", "detail"]) : dim(t("Nothing due right now.", "Nada que toque ahora.")));
|
|
13198
|
+
}
|
|
13199
|
+
if (a3 === "template") {
|
|
13200
|
+
const r2 = await api(path2, { method: "POST", body: { board, intent: "create-template" } });
|
|
13201
|
+
return out(r2, () => t("Template sent to Meta for review (utility).", "Plantilla enviada a revisi\xF3n de Meta (utilidad)."));
|
|
13202
|
+
}
|
|
13203
|
+
if (a3 === "on" || a3 === "off" || steps || minutes !== void 0) {
|
|
13204
|
+
await api(path2, { method: "POST", body: { board, intent: "set", ...a3 ? { enabled: a3 === "on" } : {}, ...steps ? { steps } : {}, ...minutes !== void 0 ? { testMinutes: minutes } : {} } });
|
|
13205
|
+
} else if (a3) throw usage(t(`Unknown action: ${a3}.`, `Acci\xF3n desconocida: ${a3}.`), "on | off | template | dry-run");
|
|
13206
|
+
const r = await api(`${path2}?board=${enc12(board)}`);
|
|
13207
|
+
return out(r, () => {
|
|
13208
|
+
const c = r.config;
|
|
13209
|
+
const head = `\xAB${r.board}\xBB: ${c.enabled ? lavender(t("on", "prendido")) : t("off", "apagado")} \xB7 ${t("touches at", "toques a los")} ${c.steps.join(", ")} ${c.testMinutes ? "min" : t("days", "d\xEDas")} \xB7 ${c.template} ${dim(`(${r.template.status ?? r.template.error ?? t("not in Meta", "sin dar de alta en Meta")})`)}`;
|
|
13210
|
+
const s2 = r.stats;
|
|
13211
|
+
const nums = `${s2.active} ${t("active", "en curso")} \xB7 ${s2.sent} ${t("sent", "enviados")} \xB7 ${s2.replied} ${t("replied", "contestaron")} \xB7 ${s2.paid} ${t("paid/closed", "pagaron o cerraron")} \xB7 ${s2.done} ${t("no reply", "sin respuesta")}`;
|
|
13212
|
+
const rows = r.recent.map((x) => ({ folio: x.folio, name: x.nombre ?? "", step: x.step, status: x.stop_reason ? `${x.status}: ${x.stop_reason}` : x.status, next: x.next_at ? new Date(x.next_at * 1e3).toISOString().slice(0, 16) : "" }));
|
|
13213
|
+
return [head, nums, rows.length ? table(rows, ["folio", "name", "step", "status", "next"]) : ""].filter(Boolean).join("\n");
|
|
13214
|
+
});
|
|
13215
|
+
}
|
|
13148
13216
|
default:
|
|
13149
|
-
throw usage(t(`Unknown boards subcommand: ${sub}.`, `Subcomando de boards desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty boards ls | create | assign | move-cards | access | rm");
|
|
13217
|
+
throw usage(t(`Unknown boards subcommand: ${sub}.`, `Subcomando de boards desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty boards ls | create | assign | move-cards | access | followups | rm");
|
|
13150
13218
|
}
|
|
13151
13219
|
}
|
|
13152
13220
|
|
|
@@ -13645,13 +13713,16 @@ var HELPS_ES = {
|
|
|
13645
13713
|
["--from / --to B", "move-cards: tableros por nombre, id o main"],
|
|
13646
13714
|
["--integration ID | --phone N | --all", "move-cards: qu\xE9 tarjetas (el filtro es obligatorio)"],
|
|
13647
13715
|
["-n, --dry-run", "move-cards: cuenta y muestra una muestra, no cambia nada"],
|
|
13648
|
-
["--yes", "move-cards: se salta la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
13716
|
+
["--yes", "move-cards: se salta la confirmaci\xF3n (obligatorio sin terminal)"],
|
|
13717
|
+
["--steps 2,7,14", "followups: d\xEDas despu\xE9s de la cotizaci\xF3n de cada toque (hasta 5)"],
|
|
13718
|
+
["--minutes on|off", "followups (staff): los pasos cuentan en minutos, para probar sin esperar d\xEDas"]
|
|
13649
13719
|
],
|
|
13650
13720
|
notes: [
|
|
13651
13721
|
"assign cambia a d\xF3nde van las tarjetas NUEVAS; move-cards trae las que ya existen (hilo, pedidos, actividad) con folio nuevo. Una tarjeta cuya conversaci\xF3n ya est\xE1 en el tablero destino se salta.",
|
|
13652
13722
|
"Leer requiere ser miembro; cambiar requiere ser due\xF1o o staff del espacio.",
|
|
13653
13723
|
"rm s\xF3lo borra un tablero vac\xEDo que no sea el principal.",
|
|
13654
|
-
"access sin flags dice qui\xE9n ve el tablero; due\xF1o y staff ven todos. Por qu\xE9 alguien lo ve: ghosty access why <correo> --workspace <espacio> --board <tablero>."
|
|
13724
|
+
"access sin flags dice qui\xE9n ve el tablero; due\xF1o y staff ven todos. Por qu\xE9 alguien lo ve: ghosty access why <correo> --workspace <espacio> --board <tablero>.",
|
|
13725
|
+
"followups: cada cotizaci\xF3n que manda el agente recibe hasta 3 toques por WhatsApp (2, 7 y 14 d\xEDas) escritos con la pl\xE1tica; paran si el cliente contesta, paga o alguien toma la pl\xE1tica. Fuera de la ventana de 24 h usa la plantilla de utilidad (template = mandarla a Meta). Cambiarlo pide el mismo permiso que mandar campa\xF1as."
|
|
13655
13726
|
]
|
|
13656
13727
|
},
|
|
13657
13728
|
cards: {
|
|
@@ -14411,6 +14482,8 @@ HELPS.channels = {
|
|
|
14411
14482
|
"ghosty channels whatsapp disable <agent-id> <number> [--dry-run]",
|
|
14412
14483
|
"ghosty channels whatsapp integrations <agent-id> [--email OTHER] [--orphans]",
|
|
14413
14484
|
"ghosty channels messenger ls <agent-id> [--orphans]",
|
|
14485
|
+
"ghosty channels messenger status <agent-id> # who answers each page, last webhook, token health",
|
|
14486
|
+
"ghosty channels messenger on|off <agent-id> <page> [--take] [--dry-run] [--yes]",
|
|
14414
14487
|
"ghosty channels whatsapp|messenger connect <agent-id> [--no-open] # opens Channels: Meta sign-in in the browser",
|
|
14415
14488
|
"ghosty channels whatsapp link <agent-id> --integration <formmy-id> --answer on|off [--forward] [--dry-run] [--yes]",
|
|
14416
14489
|
"ghosty channels whatsapp unlink <agent-id> --integration <formmy-id> [--dry-run] [--yes]",
|
|
@@ -14545,7 +14618,8 @@ HELPS.boards = {
|
|
|
14545
14618
|
"ghosty boards assign <agent-id> <board|main>",
|
|
14546
14619
|
"ghosty boards move-cards <workspace> --from <board> --to <board> [--integration ID | --phone N | --all] [--dry-run] [--yes]",
|
|
14547
14620
|
'ghosty boards rm <workspace> "Name" [--yes]',
|
|
14548
|
-
"ghosty boards access <workspace> [board|main] [--add EMAIL] [--remove EMAIL] [--restrict] [--everyone] [--until 2026-10-28|14d]"
|
|
14621
|
+
"ghosty boards access <workspace> [board|main] [--add EMAIL] [--remove EMAIL] [--restrict] [--everyone] [--until 2026-10-28|14d]",
|
|
14622
|
+
"ghosty boards followups <workspace> [board|main] [on|off|template|dry-run] [--steps 2,7,14] [--minutes on|off]"
|
|
14549
14623
|
],
|
|
14550
14624
|
flags: [
|
|
14551
14625
|
["--add / --remove EMAIL", "access: add to or take off the board's \xABonly these people\xBB list (repeatable or comma-separated; only workspace members)"],
|
|
@@ -14556,10 +14630,12 @@ HELPS.boards = {
|
|
|
14556
14630
|
["--from / --to B", "move-cards: boards by name, id or main"],
|
|
14557
14631
|
["--integration ID | --phone N | --all", "move-cards: which cards (a filter is required)"],
|
|
14558
14632
|
["-n, --dry-run", "move-cards: count and show a sample, change nothing"],
|
|
14559
|
-
["--yes", "move-cards: skip the confirmation (required without a terminal)"]
|
|
14633
|
+
["--yes", "move-cards: skip the confirmation (required without a terminal)"],
|
|
14634
|
+
["--steps 2,7,14", "followups: days after the quote for each touch (up to 5)"],
|
|
14635
|
+
["--minutes on|off", "followups (staff): count the steps in minutes, to test without waiting days"]
|
|
14560
14636
|
],
|
|
14561
|
-
examples: ["ghosty boards ls siiqtec", 'ghosty boards create siiqtec "Siiqtec - Ixmiquilpan" --columns-from main', 'ghosty boards assign <agent-id> "Siiqtec - Ixmiquilpan"', 'ghosty boards move-cards siiqtec --from main --to "Siiqtec - Ixmiquilpan" --integration 6a3b02ad\u2026 --dry-run'],
|
|
14562
|
-
notes: ["assign changes where NEW cards go; move-cards brings the existing ones (thread, orders, activity) with a new folio. A card whose conversation is already on the target board is skipped.", "Reading needs membership; changing needs owner or staff of the workspace.", "rm only deletes an empty board that is not the main one.", "access without flags shows who sees the board; owner and staff always see every board. Why someone sees it: ghosty access why <email> --workspace <ws> --board <board>."],
|
|
14637
|
+
examples: ["ghosty boards ls siiqtec", "ghosty boards followups siiqtec main template", "ghosty boards followups siiqtec main on", 'ghosty boards create siiqtec "Siiqtec - Ixmiquilpan" --columns-from main', 'ghosty boards assign <agent-id> "Siiqtec - Ixmiquilpan"', 'ghosty boards move-cards siiqtec --from main --to "Siiqtec - Ixmiquilpan" --integration 6a3b02ad\u2026 --dry-run'],
|
|
14638
|
+
notes: ["assign changes where NEW cards go; move-cards brings the existing ones (thread, orders, activity) with a new folio. A card whose conversation is already on the target board is skipped.", "Reading needs membership; changing needs owner or staff of the workspace.", "rm only deletes an empty board that is not the main one.", "access without flags shows who sees the board; owner and staff always see every board. Why someone sees it: ghosty access why <email> --workspace <ws> --board <board>.", "followups: every quote the agent sends gets up to 3 WhatsApp touches (2, 7 and 14 days) written from the conversation; they stop when the customer replies, pays or someone takes the chat. Outside the 24 h window it uses the utility template (template = submit it to Meta). Changing it takes the same permission as sending campaigns."],
|
|
14563
14639
|
learn: `${REF}#tablero`
|
|
14564
14640
|
};
|
|
14565
14641
|
HELPS.cards = {
|
|
@@ -16906,6 +16982,8 @@ ${bold("Configure an agent")}
|
|
|
16906
16982
|
channels whatsapp|messenger connect <id> Opens the agent's Channels page to connect a number or page with Meta (browser sign-in) [--no-open]
|
|
16907
16983
|
channels whatsapp integrations <id> Its owner's WhatsApp Business numbers in Formmy (number, who answers today, who answered last, Integration id) [--orphans: answered by nobody but with turns]
|
|
16908
16984
|
channels messenger ls <id> The workspace's Messenger pages: who answers now and who answered last [--orphans]
|
|
16985
|
+
channels messenger status <id> Each page: who answers, last webhook and token health (asks Meta now)
|
|
16986
|
+
channels messenger on|off <id> <page> Answer a page with this agent, or stop (off keeps logging to the board) [--take --dry-run --yes]
|
|
16909
16987
|
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]
|
|
16910
16988
|
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] [--board NAME|agent] [--dry-run]
|
|
16911
16989
|
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]
|
|
@@ -16913,7 +16991,7 @@ ${bold("Configure an agent")}
|
|
|
16913
16991
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
16914
16992
|
channels wa status|pause <id> Personal WhatsApp: how it is / pause it (keeps the session)
|
|
16915
16993
|
channels wa groups ls|enable|disable|set|create <id> [group] Personal WhatsApp groups it answers, and as whom [--role equipo|cliente] [--wake mention|all] [--name "New name"] [--dry-run]
|
|
16916
|
-
boards ls|create|assign|move-cards|access|rm A workspace's boards: create (--columns-from), where an agent sends cards, move cards, who sees each one
|
|
16994
|
+
boards ls|create|assign|move-cards|access|followups|rm A workspace's boards: create (--columns-from), where an agent sends cards, move cards, who sees each one, quote follow-ups
|
|
16917
16995
|
cards ls <id> Recent cards on its sales board [--q TEXT] [--paused] [--limit 20]
|
|
16918
16996
|
cards show <id> <card> A card's thread: who wrote, text, attachments and whether gs kept a copy (folio, phone or id)
|
|
16919
16997
|
cards archive <id> Archive cards in bulk (reversible) --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -16936,7 +17014,7 @@ ${bold("Sites")} ${dim("(sites your agents publish at <slug>.ghosty.page)")}
|
|
|
16936
17014
|
sites pin <slug|id> Pin it: never pauses, no banner ($49 USD/yr or $5/mo, includes up to 3 sites) [--interval year|month] [--currency usd|mxn] [--add-pack: 3 more]
|
|
16937
17015
|
sites unpin <slug|id> Release its slot (back to the Free rule: 30 days + notice)
|
|
16938
17016
|
sites search <slug|id> How Google finds it: clicks, impressions, searches, indexed or not [--days 28]
|
|
16939
|
-
sites domain add|verify|rm <slug> <dom> Custom domain for
|
|
17017
|
+
sites domain add|verify|rm <slug> <dom> Custom domain for a site or app (DNS record \u2192 verify \u2192 HTTPS) [ls <slug>: list]
|
|
16940
17018
|
sites pins Your pinned-sites subscription and slots [--cancel | --resume]
|
|
16941
17019
|
sites publish <file.html|folder> Publish a house site (staff): no owner, no expiry, no banner [--title] [--slug S] [--site <slug|id>: update that one]
|
|
16942
17020
|
sites slug <slug|id> <new-slug> Change a site's slug (staff)
|
|
@@ -17122,6 +17200,8 @@ ${bold("Configurar un agente")}
|
|
|
17122
17200
|
channels whatsapp|messenger connect <id> Abre la p\xE1gina Canales del agente para conectar un n\xFAmero o una p\xE1gina con Meta (inicio de sesi\xF3n en el navegador) [--no-open]
|
|
17123
17201
|
channels whatsapp integrations <id> Los n\xFAmeros de WhatsApp Business de su due\xF1o en Formmy (n\xFAmero, qui\xE9n contesta hoy, qui\xE9n contest\xF3 al \xFAltimo, id de la Integration) [--orphans: sin qui\xE9n conteste pero con turnos]
|
|
17124
17202
|
channels messenger ls <id> Las p\xE1ginas de Messenger del espacio: qui\xE9n contesta hoy y qui\xE9n contest\xF3 al \xFAltimo [--orphans]
|
|
17203
|
+
channels messenger status <id> Cada p\xE1gina: qui\xE9n contesta, \xFAltimo webhook y salud del token (le pregunta a Meta en el momento)
|
|
17204
|
+
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]
|
|
17125
17205
|
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]
|
|
17126
17206
|
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] [--board NOMBRE|agent] [--dry-run]
|
|
17127
17207
|
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]
|
|
@@ -17129,7 +17209,7 @@ ${bold("Configurar un agente")}
|
|
|
17129
17209
|
channels wa pair <id> --phone N Vincula un WhatsApp personal con c\xF3digo (sin QR)
|
|
17130
17210
|
channels wa status|pause <id> WhatsApp personal: c\xF3mo est\xE1 / pausarlo (conserva la sesi\xF3n)
|
|
17131
17211
|
channels wa groups ls|enable|disable|set|create <id> [grupo] Grupos de WhatsApp personal que contesta, y como qui\xE9n [--role equipo|cliente] [--wake mention|all] [--name "Nombre nuevo"] [--dry-run]
|
|
17132
|
-
boards ls|create|assign|move-cards|access|rm Los tableros de un espacio: crear (--columns-from), a d\xF3nde manda tarjetas un agente, mover tarjetas, qui\xE9n ve cada uno
|
|
17212
|
+
boards ls|create|assign|move-cards|access|followups|rm Los tableros de un espacio: crear (--columns-from), a d\xF3nde manda tarjetas un agente, mover tarjetas, qui\xE9n ve cada uno, seguimiento de cotizaciones
|
|
17133
17213
|
cards ls <id> Tarjetas recientes de su tablero de ventas [--q TEXTO] [--paused] [--limit 20]
|
|
17134
17214
|
cards show <id> <tarjeta> El hilo de una tarjeta: qui\xE9n escribi\xF3, texto, adjuntos y si gs guard\xF3 copia (folio, tel\xE9fono o id)
|
|
17135
17215
|
cards archive <id> Archiva tarjetas en bloque (reversible) --integration X | --column X | --before 30d [--dry-run]
|
|
@@ -17152,7 +17232,7 @@ ${bold("Sitios")} ${dim("(los sitios que publican tus agentes en <slug>.ghosty.
|
|
|
17152
17232
|
sites pin <slug|id> F\xEDjalo: no se pausa y va sin franja ($49 USD al a\xF1o o $5 al mes, incluye hasta 3 sitios) [--interval year|month] [--currency usd|mxn] [--add-pack: 3 m\xE1s]
|
|
17153
17233
|
sites unpin <slug|id> Suelta su lugar (vuelve a la regla Gratis: 30 d\xEDas + aviso)
|
|
17154
17234
|
sites pins Tu suscripci\xF3n de Sitios fijos y sus lugares [--cancel | --resume]
|
|
17155
|
-
sites domain add|verify|rm <slug> <dom> Dominio propio para
|
|
17235
|
+
sites domain add|verify|rm <slug> <dom> Dominio propio para un sitio o app (registro DNS \u2192 verificar \u2192 HTTPS) [ls <slug>: lista]
|
|
17156
17236
|
sites publish <archivo.html|carpeta> Publica un sitio de la casa (staff): sin due\xF1o, sin caducidad, sin franja [--title] [--slug S] [--site <slug|id>: actualiza \xE9se]
|
|
17157
17237
|
sites slug <slug|id> <slug-nuevo> Cambia el slug de un sitio (staff)
|
|
17158
17238
|
|
|
@@ -17370,6 +17450,7 @@ async function main() {
|
|
|
17370
17450
|
"key-column": { type: "string" },
|
|
17371
17451
|
"unset-env": { type: "string" },
|
|
17372
17452
|
orphans: { type: "boolean" },
|
|
17453
|
+
take: { type: "boolean" },
|
|
17373
17454
|
skipped: { type: "boolean" },
|
|
17374
17455
|
paused: { type: "boolean" },
|
|
17375
17456
|
email: { type: "string" },
|
|
@@ -17386,6 +17467,8 @@ async function main() {
|
|
|
17386
17467
|
enable: { type: "string" },
|
|
17387
17468
|
disable: { type: "string" },
|
|
17388
17469
|
"columns-from": { type: "string" },
|
|
17470
|
+
steps: { type: "string" },
|
|
17471
|
+
minutes: { type: "string" },
|
|
17389
17472
|
add: { type: "string", multiple: true },
|
|
17390
17473
|
remove: { type: "string", multiple: true },
|
|
17391
17474
|
everyone: { type: "boolean" },
|
|
@@ -17545,7 +17628,7 @@ async function main() {
|
|
|
17545
17628
|
const tokens = splitTokens(pos, v);
|
|
17546
17629
|
globals.token = tokens.session;
|
|
17547
17630
|
globals.profile = v.profile;
|
|
17548
|
-
if (v.version) return out({ version: "0.
|
|
17631
|
+
if (v.version) return out({ version: "0.87.0" }, () => "0.87.0");
|
|
17549
17632
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
17550
17633
|
const context = (await readConfig()).workspace;
|
|
17551
17634
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -17652,7 +17735,7 @@ async function main() {
|
|
|
17652
17735
|
case "board":
|
|
17653
17736
|
return boardCmd(sub, a1, v, a2);
|
|
17654
17737
|
case "boards":
|
|
17655
|
-
return boardsCmd(sub, a1, a2, v, context);
|
|
17738
|
+
return boardsCmd(sub, a1, a2, v, context, pos[4]);
|
|
17656
17739
|
case "channels":
|
|
17657
17740
|
if (a1 === "connect" && ["whatsapp", "wa", "messenger", "fb"].includes(sub ?? "")) {
|
|
17658
17741
|
if (!a2) throw usage(t("Missing agent id.", "Falta el id del agente."), `ghosty channels ${sub} connect <agent-id>`);
|
|
@@ -17748,7 +17831,7 @@ async function main() {
|
|
|
17748
17831
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
17749
17832
|
}
|
|
17750
17833
|
}
|
|
17751
|
-
var notice = updateNotice("0.
|
|
17834
|
+
var notice = updateNotice("0.87.0").catch(() => null);
|
|
17752
17835
|
main().then(
|
|
17753
17836
|
async () => {
|
|
17754
17837
|
const n = await notice;
|
package/package.json
CHANGED