@ghostystudio/cli 0.57.1 → 0.58.1
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 +6 -2
- package/dist/index.js +99 -35
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ ghosty schedule add|ls|rm <id> … --teams <workspace>#<room>[/<thread-id>] #
|
|
|
84
84
|
|
|
85
85
|
ghosty me files ls|get|export|upload|rm [--q TEXT] [--kind image|video|audio|document|other] [--cursor C]
|
|
86
86
|
ghosty me memories ls|add|edit|rm
|
|
87
|
-
ghosty conversations archive|rm <id> --kind test|channel [--before 7d] [--dry-run]
|
|
87
|
+
ghosty conversations archive|rm <id> --kind test|channel|personal [--before 7d] [--dry-run]
|
|
88
88
|
ghosty agents docs dedupe [--dry-run] # your account: merge documents with the same content
|
|
89
89
|
# Ghosty staff
|
|
90
90
|
ghosty conversations ls --user EMAIL [--since 30d] · conversations show <id> <conv> --why|--tools
|
|
@@ -109,6 +109,10 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
|
|
|
109
109
|
|
|
110
110
|
Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
111
111
|
|
|
112
|
+
### Changes in 0.58.1
|
|
113
|
+
|
|
114
|
+
- `agents docs add|replace --file` sends the file type from its extension. Before, the server stored every CLI upload as `application/octet-stream`, and a PDF reached WhatsApp customers as `.bin`.
|
|
115
|
+
|
|
112
116
|
### Changes in 0.57.1 (0.57.0 + the 0.56.1 factory fix)
|
|
113
117
|
|
|
114
118
|
- `sites pin <slug>` / `sites unpin <slug>` / `sites pins [--cancel|--resume]`: «Pinned sites» — $49 USD/yr or $5 USD/mo ($990 / $99 MXN), includes up to 3 sites per pack; a pinned site never pauses and has no banner. `--interval year|month`, `--currency usd|mxn`, `--add-pack`.
|
|
@@ -136,7 +140,7 @@ Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
|
136
140
|
### Changes in 0.52.0
|
|
137
141
|
|
|
138
142
|
- `agents embed <id>` customizes the web widget: `--title`, `--subtitle`, `--avatar URL|none`, `--icon chat|avatar|ghost`, `--placeholder`, `--position right|left`, `--offset X[,Y]`, `--theme light|dark|auto`, `--bubble-text`, `--auto-open S|off`, `--starters "a|b"` (up to 4 of yours; Ghosty's never show). The pasted `<script>` doesn't change.
|
|
139
|
-
- Fine style without free CSS: `--style '{json}'|none` (fontFamily from a Google Fonts allow-list, radius 0–24, header/bubble/input/send/launcher colors, titleUppercase, statusDot, sendArrow), shortcuts `--font` and `--
|
|
143
|
+
- Fine style without free CSS: `--style '{json}'|none` (fontFamily from a Google Fonts allow-list, radius 0–24, header/bubble/input/send/launcher colors, titleUppercase, statusDot, sendArrow, typing, typingColor), shortcuts `--font`, `--radius`, `--typing bounce|flow|flashing|shimmer` and `--typing-color`.
|
|
140
144
|
- Theme source: `--theme-source teams` (your Ghosty Teams workspace brand, `--workspace SLUG`) or `--theme-source site --site-url URL` (your site's CSS colors), imported as editable values. `agents embed <id> theme` exports it as JSON; `--style-file theme.json` applies it back.
|
|
141
145
|
|
|
142
146
|
### Changes in 0.51.0
|
package/dist/index.js
CHANGED
|
@@ -7863,11 +7863,11 @@ var SERVER_MESSAGES = [
|
|
|
7863
7863
|
["la caja ACP {} arranc\xF3 en error: {}", "ACP box {} started in error: {}"],
|
|
7864
7864
|
["la caja ACP {} no lleg\xF3 a running en 90s", "ACP box {} didn't reach running in 90s"],
|
|
7865
7865
|
["la caja {} no lleg\xF3 a running (\xFAltimo estado: {})", "box {} didn't reach running (last state: {})"],
|
|
7866
|
+
["la caja {} no arranc\xF3: {}", "box {} failed to boot: {}"],
|
|
7866
7867
|
["la caja del agente naci\xF3 muda (no arranc\xF3 {}-runtime): {}", "the agent's box came up mute ({}-runtime didn't start): {}"],
|
|
7867
7868
|
["no se pudo re-rutear tras caja muerta", "couldn't re-route after a dead box"],
|
|
7868
7869
|
["fleet route race sin ganador", "fleet route race with no winner"],
|
|
7869
7870
|
["create: respuesta sin sandboxId", "create: response without sandboxId"],
|
|
7870
|
-
["warmpool.claim: respuesta sin sandboxId", "warmpool.claim: response without sandboxId"],
|
|
7871
7871
|
["expose: respuesta sin url", "expose: response without url"],
|
|
7872
7872
|
["expose-raw: respuesta sin hostPort", "expose-raw: response without hostPort"],
|
|
7873
7873
|
// — Cajas compartidas: voz, render, video, ortografía, eventos
|
|
@@ -8468,7 +8468,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
|
|
|
8468
8468
|
const req = httpsRequest(`${base}${path}`, {
|
|
8469
8469
|
method: "POST",
|
|
8470
8470
|
timeout: timeoutMs,
|
|
8471
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
8471
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.58.1"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
8472
8472
|
}, (res) => {
|
|
8473
8473
|
let buf = "";
|
|
8474
8474
|
res.on("data", (c) => buf += c);
|
|
@@ -8510,7 +8510,7 @@ async function request(path, opts = {}, retried = false) {
|
|
|
8510
8510
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
8511
8511
|
headers: {
|
|
8512
8512
|
authorization: `Bearer ${token}`,
|
|
8513
|
-
"user-agent": `ghosty-cli/${"0.
|
|
8513
|
+
"user-agent": `ghosty-cli/${"0.58.1"}`,
|
|
8514
8514
|
"accept-language": lang(),
|
|
8515
8515
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
8516
8516
|
...opts.headers
|
|
@@ -9095,7 +9095,7 @@ ${dim(t(`only ${workspace} (ghosty use) \xB7 all: --all`, `s\xF3lo ${workspace}
|
|
|
9095
9095
|
function parseEnv(raw) {
|
|
9096
9096
|
if (!raw) return void 0;
|
|
9097
9097
|
const env = {};
|
|
9098
|
-
for (const pair of raw.split(
|
|
9098
|
+
for (const pair of raw.split(/,(?=[A-Za-z_][A-Za-z0-9_]*=)/)) {
|
|
9099
9099
|
const i = pair.indexOf("=");
|
|
9100
9100
|
if (i < 1) throw usage(t(`Bad --env entry: ${pair}.`, `Entrada de --env inv\xE1lida: ${pair}.`), t("Example", "Ejemplo") + ": --env GHOSTY_THINKING_EFFORT=max");
|
|
9101
9101
|
env[pair.slice(0, i).trim()] = pair.slice(i + 1);
|
|
@@ -9731,10 +9731,12 @@ async function agentsEmbed(id, v, action) {
|
|
|
9731
9731
|
if (body.themeSource === void 0) body.themeSource = "site";
|
|
9732
9732
|
}
|
|
9733
9733
|
if (body.themeSource === "teams" && v.workspace) body.teamsWorkspace = v.workspace;
|
|
9734
|
-
if (v.font !== void 0 || v.radius !== void 0) {
|
|
9734
|
+
if (v.font !== void 0 || v.radius !== void 0 || v.typing !== void 0 || v["typing-color"] !== void 0) {
|
|
9735
9735
|
const st = body.style && typeof body.style === "object" ? body.style : {};
|
|
9736
9736
|
if (v.font !== void 0) st.fontFamily = clear(v.font);
|
|
9737
9737
|
if (v.radius !== void 0) st.radius = v.radius === "" || v.radius === "none" ? null : Number(v.radius);
|
|
9738
|
+
if (v.typing !== void 0) st.typing = clear(v.typing);
|
|
9739
|
+
if (v["typing-color"] !== void 0) st.typingColor = clear(v["typing-color"]);
|
|
9738
9740
|
body.style = st;
|
|
9739
9741
|
}
|
|
9740
9742
|
if (v.rotate) body.rotate = true;
|
|
@@ -10303,6 +10305,7 @@ ${bold("Partner space")} ${dim("(you, signed in as the space owner)")}
|
|
|
10303
10305
|
partner credentials rotate <keyId> [--grace MIN] New secret, same keyId (old one valid MIN, default 60)
|
|
10304
10306
|
partner credentials revoke <keyId> Revoke it (idempotent)
|
|
10305
10307
|
partner audit Who did what, when
|
|
10308
|
+
partner usage [--tenant ID] [--from YYYY-MM-DD] [--to YYYY-MM-DD] Turns, tokens, cost and errors per business (30 days by default)
|
|
10306
10309
|
|
|
10307
10310
|
${bold("Shared agents (solo-MCP)")} ${dim("(--agent SLUG picks another agent of the partner: nik-admin, nik-public\u2026)")}
|
|
10308
10311
|
partner agent get [--agent SLUG] The agent template and its version
|
|
@@ -10348,6 +10351,7 @@ ${bold("Espacio de partner")} ${dim("(t\xFA, con sesi\xF3n como due\xF1a del es
|
|
|
10348
10351
|
partner credentials rotate <keyId> [--grace MIN] Secreto nuevo, mismo keyId (el viejo vale MIN, default 60)
|
|
10349
10352
|
partner credentials revoke <keyId> La revoca (idempotente)
|
|
10350
10353
|
partner audit Qui\xE9n hizo qu\xE9 y cu\xE1ndo
|
|
10354
|
+
partner usage [--tenant ID] [--from AAAA-MM-DD] [--to AAAA-MM-DD] Turnos, tokens, costo y fallas por negocio (30 d\xEDas por default)
|
|
10351
10355
|
|
|
10352
10356
|
${bold("Agentes compartidos (solo-MCP)")} ${dim("(--agent SLUG elige otro agente del partner: nik-admin, nik-public\u2026)")}
|
|
10353
10357
|
partner agent get [--agent SLUG] La plantilla del agente y su versi\xF3n
|
|
@@ -10404,7 +10408,7 @@ async function call(path, v, init = {}) {
|
|
|
10404
10408
|
"x-ghosty-ts": ts,
|
|
10405
10409
|
"x-ghosty-sig": sig,
|
|
10406
10410
|
"content-type": "application/json",
|
|
10407
|
-
"user-agent": `ghosty-cli/${"0.
|
|
10411
|
+
"user-agent": `ghosty-cli/${"0.58.1"}`
|
|
10408
10412
|
},
|
|
10409
10413
|
body: method === "GET" ? void 0 : raw
|
|
10410
10414
|
});
|
|
@@ -10647,6 +10651,29 @@ async function partnerCmd(sub, a1, a2, v, a3) {
|
|
|
10647
10651
|
const r = await json("/api/v2/partner/audit", v, { ownerOnly: true });
|
|
10648
10652
|
return out(r, () => table(r.events.map((e) => ({ when: fmt(e.ts), action: e.action, externalId: e.externalId, actor: e.actor })), ["when", "action", "externalId", "actor"]));
|
|
10649
10653
|
}
|
|
10654
|
+
case "usage": {
|
|
10655
|
+
const q = new URLSearchParams();
|
|
10656
|
+
if (v.tenant) q.set("externalId", v.tenant);
|
|
10657
|
+
if (v.from) q.set("from", v.from);
|
|
10658
|
+
if (v.to) q.set("to", v.to);
|
|
10659
|
+
const r = await json(
|
|
10660
|
+
`/api/v2/partner/usage${q.size ? `?${q}` : ""}`,
|
|
10661
|
+
v
|
|
10662
|
+
);
|
|
10663
|
+
return out(
|
|
10664
|
+
r,
|
|
10665
|
+
() => r.tenants.length ? table(
|
|
10666
|
+
r.tenants.map((x) => ({
|
|
10667
|
+
tenant: x.name ? `${x.name} (${x.externalId})` : x.externalId,
|
|
10668
|
+
turns: x.turns,
|
|
10669
|
+
tokens: x.tokens,
|
|
10670
|
+
usd: x.costUsd.toFixed(4),
|
|
10671
|
+
errors: Object.entries(x.errors).map(([k, n]) => `${k}\xD7${n}`).join(" ") || "\u2014"
|
|
10672
|
+
})),
|
|
10673
|
+
["tenant", "turns", "tokens", "usd", "errors"]
|
|
10674
|
+
) : dim(t("No usage in that range.", "Sin consumo en ese rango."))
|
|
10675
|
+
);
|
|
10676
|
+
}
|
|
10650
10677
|
case "try":
|
|
10651
10678
|
return tryCmd(a1, a2, v);
|
|
10652
10679
|
case "wa":
|
|
@@ -10984,7 +11011,7 @@ async function agentDocsCmd(sub, id, docs, v) {
|
|
|
10984
11011
|
if (!v.url === !v.file) throw usage(t("Use --url URL or --file PATH (one of them).", "Usa --url URL o --file RUTA (uno de los dos)."), t("Example", "Ejemplo") + ': ghosty agents docs add <agent-id> --url https://\u2026/lista.pdf --description "Precios 2026"');
|
|
10985
11012
|
if (v.grant && !["read", "write", "no"].includes(v.grant)) throw usage(t("--grant takes read, write or no.", "--grant acepta read, write o no."));
|
|
10986
11013
|
const body = {
|
|
10987
|
-
...v.url ? { url: v.url } : { contentBase64: (await readFile6(v.file)).toString("base64"), name: v.name ?? basename3(v.file) },
|
|
11014
|
+
...v.url ? { url: v.url } : { contentBase64: (await readFile6(v.file)).toString("base64"), name: v.name ?? basename3(v.file), ...mimeField(v.file) },
|
|
10988
11015
|
...v.url && v.name ? { name: v.name } : {},
|
|
10989
11016
|
...v.description ? { description: v.description } : {},
|
|
10990
11017
|
grant: v.grant === "no" ? false : v.grant === "write" || v.write ? "write" : "read",
|
|
@@ -11003,7 +11030,7 @@ async function agentDocsCmd(sub, id, docs, v) {
|
|
|
11003
11030
|
doc = need2(doc, t("document (id or exact name)", "el documento (id o nombre exacto)"), ex);
|
|
11004
11031
|
if (!v.url === !v.file) throw usage(t("Use --url URL or --file PATH (one of them).", "Usa --url URL o --file RUTA (uno de los dos)."), t("Example", "Ejemplo") + ": " + ex);
|
|
11005
11032
|
const body = {
|
|
11006
|
-
...v.url ? { url: v.url } : { contentBase64: (await readFile6(v.file)).toString("base64") },
|
|
11033
|
+
...v.url ? { url: v.url } : { contentBase64: (await readFile6(v.file)).toString("base64"), ...mimeField(v.file) },
|
|
11007
11034
|
...v.note ? { note: v.note } : {}
|
|
11008
11035
|
};
|
|
11009
11036
|
const r = await api(agentPath2(id, `/documents/${enc6(doc)}/versions`), { method: "POST", body });
|
|
@@ -11119,6 +11146,33 @@ async function turnsGrep(id, text, v) {
|
|
|
11119
11146
|
out(r, () => rows.length ? `${table(rows, ["at", "who", "turn", "state", "session", "text"])}
|
|
11120
11147
|
${dim(`${t("open one", "abre uno")}: ghosty turns show ${id} <turn>`)}` : dim(t(`Nothing says \xAB${text}\xBB${v.since ? ` since ${v.since}` : ""}.`, `Nada dice \xAB${text}\xBB${v.since ? ` desde ${v.since}` : ""}.`)));
|
|
11121
11148
|
}
|
|
11149
|
+
function mimeField(path) {
|
|
11150
|
+
const types = {
|
|
11151
|
+
pdf: "application/pdf",
|
|
11152
|
+
png: "image/png",
|
|
11153
|
+
jpg: "image/jpeg",
|
|
11154
|
+
jpeg: "image/jpeg",
|
|
11155
|
+
gif: "image/gif",
|
|
11156
|
+
webp: "image/webp",
|
|
11157
|
+
mp3: "audio/mpeg",
|
|
11158
|
+
ogg: "audio/ogg",
|
|
11159
|
+
wav: "audio/wav",
|
|
11160
|
+
m4a: "audio/mp4",
|
|
11161
|
+
mp4: "video/mp4",
|
|
11162
|
+
mov: "video/quicktime",
|
|
11163
|
+
csv: "text/csv",
|
|
11164
|
+
md: "text/markdown",
|
|
11165
|
+
txt: "text/plain",
|
|
11166
|
+
html: "text/html",
|
|
11167
|
+
json: "application/json",
|
|
11168
|
+
zip: "application/zip",
|
|
11169
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
11170
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
11171
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
11172
|
+
};
|
|
11173
|
+
const mime = types[path.split(".").pop()?.toLowerCase() ?? ""];
|
|
11174
|
+
return mime ? { mime } : {};
|
|
11175
|
+
}
|
|
11122
11176
|
async function turnShow(id, turnId, full = false) {
|
|
11123
11177
|
id = need2(id, t("agent id", "el id del agente"), "ghosty turns show <agent-id> [turn-id|last] [--full]");
|
|
11124
11178
|
const r = await api(agentPath2(id, `/turns/${enc6(turnId ?? "last")}`));
|
|
@@ -11487,9 +11541,10 @@ async function channelsCmd(kind, sub, id, ref, v) {
|
|
|
11487
11541
|
answers: n2.mine ? lavender(t("this agent", "este agente")) : n2.recordsOnly ? t("this agent (records only)", "este agente (s\xF3lo registra)") : n2.takenByOther ? t("another agent", "otro agente") : dim(t("nobody (silent)", "nadie (en silencio)")),
|
|
11488
11542
|
"formmy forwards": fwd(n2),
|
|
11489
11543
|
"ads only": n2.adsOnly ? lavender(t("yes", "s\xED")) : "",
|
|
11544
|
+
board: n2.board ? n2.board.name : dim(t("the agent's", "el del agente")),
|
|
11490
11545
|
id: n2.id
|
|
11491
11546
|
}));
|
|
11492
|
-
return out(cur, () => rows.length ? table(rows, ["number", "answers", "formmy forwards", "ads only", "id"]) : dim(t(`No WhatsApp Business numbers yet. Pair one at ${cur.salesUrl}`, `Todav\xEDa no hay n\xFAmeros de WhatsApp Business. Parea uno en ${cur.salesUrl}`)));
|
|
11547
|
+
return out(cur, () => rows.length ? table(rows, ["number", "answers", "formmy forwards", "ads only", "board", "id"]) : dim(t(`No WhatsApp Business numbers yet. Pair one at ${cur.salesUrl}`, `Todav\xEDa no hay n\xFAmeros de WhatsApp Business. Parea uno en ${cur.salesUrl}`)));
|
|
11493
11548
|
}
|
|
11494
11549
|
if (sub !== "enable" && sub !== "disable") throw usage(t(`Unknown subcommand: ${sub}.`, `Subcomando desconocido: ${sub}.`), t("Try", "Prueba") + ": ghosty channels whatsapp ls | enable | disable | integrations | link | unlink | history \xB7 ghosty channels wa import | status | pause | groups");
|
|
11495
11550
|
if (!ref) throw usage(t("Missing number.", "Falta el n\xFAmero."), t("Example", "Ejemplo") + `: ghosty channels whatsapp ${sub} ${id} +52 55 1234 5678`);
|
|
@@ -11652,19 +11707,21 @@ async function linkCmd(sub, id, v) {
|
|
|
11652
11707
|
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 ${sub} <agent-id> --integration <formmy-integration-id> --answer off --dry-run`);
|
|
11653
11708
|
if (v["ads-only"] !== void 0 && v["ads-only"] !== "on" && v["ads-only"] !== "off") throw usage(t("--ads-only takes on or off.", "--ads-only acepta on u off."));
|
|
11654
11709
|
const adsOnly = v["ads-only"] === void 0 ? void 0 : v["ads-only"] === "on";
|
|
11655
|
-
|
|
11710
|
+
const board = v.board === void 0 ? void 0 : /^(agent|agente)$/i.test(v.board) ? null : v.board;
|
|
11711
|
+
const boardFlag = v.board !== void 0 ? ` --board ${JSON.stringify(v.board)}` : "";
|
|
11712
|
+
if (sub === "link" && (adsOnly !== void 0 || board !== void 0) && v.answer === void 0) {
|
|
11656
11713
|
const path2 = `/api/v2/agents/${enc7(id)}/whatsapp/link`;
|
|
11657
|
-
const r2 = await api(path2, { method: "POST", body: { integrationId: v.integration, adsOnly, ...v["dry-run"] ? { dryRun: true } : {} } });
|
|
11714
|
+
const r2 = await api(path2, { method: "POST", body: { integrationId: v.integration, ...adsOnly !== void 0 ? { adsOnly } : {}, ...board !== void 0 ? { board } : {}, ...v["dry-run"] ? { dryRun: true } : {} } });
|
|
11658
11715
|
return out(r2, () => `${r2.plan.map((x) => serverText(x)).join("\n")}${v["dry-run"] ? `
|
|
11659
|
-
${dim(applyHint(`ghosty channels whatsapp link ${id} --integration ${v.integration} --ads-only ${v["ads-only"]}`))}` : ""}`);
|
|
11716
|
+
${dim(applyHint(`ghosty channels whatsapp link ${id} --integration ${v.integration}${v["ads-only"] ? ` --ads-only ${v["ads-only"]}` : ""}${boardFlag}`))}` : ""}`);
|
|
11660
11717
|
}
|
|
11661
11718
|
if (sub === "link" && v.answer !== "on" && v.answer !== "off") throw usage(t("Missing --answer on|off.", "Falta --answer on|off."), t("on = this agent answers real customers \xB7 off = it only records (add --forward so gs still sees the conversations)", "on = este agente contesta a clientes reales \xB7 off = s\xF3lo registra (agrega --forward para que gs siga viendo las conversaciones)"));
|
|
11662
11719
|
const path = `/api/v2/agents/${enc7(id)}/whatsapp/link`;
|
|
11663
11720
|
if (v["partner-agent"] && !v["partner-tenant"]) throw usage(t("--partner-agent needs --partner-tenant <externalId>.", "--partner-agent necesita --partner-tenant <externalId>."));
|
|
11664
11721
|
const partner = v["partner-tenant"] ? { partnerExternalId: v["partner-tenant"], ...v["partner-agent"] ? { partnerAgentSlug: v["partner-agent"] } : {} } : {};
|
|
11665
|
-
const body = { integrationId: v.integration, ...sub === "unlink" ? { unlink: true } : { answer: v.answer === "on", ...v.forward ? { forward: true } : {}, ...adsOnly !== void 0 ? { adsOnly } : {}, ...partner } };
|
|
11722
|
+
const body = { integrationId: v.integration, ...sub === "unlink" ? { unlink: true } : { answer: v.answer === "on", ...v.forward ? { forward: true } : {}, ...adsOnly !== void 0 ? { adsOnly } : {}, ...board !== void 0 ? { board } : {}, ...partner } };
|
|
11666
11723
|
const partnerFlags = v["partner-tenant"] ? ` --partner-tenant ${v["partner-tenant"]}${v["partner-agent"] ? ` --partner-agent ${v["partner-agent"]}` : ""}` : "";
|
|
11667
|
-
const cmd = `ghosty channels whatsapp ${sub} ${id} --integration ${v.integration}${sub === "link" ? ` --answer ${v.answer}${v.forward ? " --forward" : ""}${v["ads-only"] ? ` --ads-only ${v["ads-only"]}` : ""}${partnerFlags}` : ""}`;
|
|
11724
|
+
const cmd = `ghosty channels whatsapp ${sub} ${id} --integration ${v.integration}${sub === "link" ? ` --answer ${v.answer}${v.forward ? " --forward" : ""}${v["ads-only"] ? ` --ads-only ${v["ads-only"]}` : ""}${boardFlag}${partnerFlags}` : ""}`;
|
|
11668
11725
|
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
11669
11726
|
const text = `${plan.plan.map((x) => serverText(x)).join("\n")}
|
|
11670
11727
|
${dim(`Formmy: ${plan.formmy.before.url ?? "null"} \u2192 ${plan.formmy.after.url ?? "null"} (${t("as", "como")} ${plan.formmy.by})`)}`;
|
|
@@ -12039,7 +12096,7 @@ var HELPS_ES = {
|
|
|
12039
12096
|
["--engine E --dry-run", "set: qu\xE9 hace cambiar de motor (sesiones que se olvidan, caja que se levanta y cu\xE1l se destruye, si est\xE1 trabajando) sin cambiarlo; cada hilo conserva su conversaci\xF3n"],
|
|
12040
12097
|
["--toolsets LIST", "set: grupos de tools de gs que recibe (crm, sales\u2026): una lista reemplaza; +x / -x agrega o quita"],
|
|
12041
12098
|
["--prompt-base ID", "set: el prompt de este agente = el prompt de ese agente + --prompt-overlay; se regenera cuando cambia la base. none = desliga (conserva el prompt de hoy)"],
|
|
12042
|
-
["--prompt-overlay FILE", 'set: JSON {"edits":[{"what","find","replace","regex"?,"all"?}]}, aplicados en orden; cada uno debe encontrar su lugar o no cambia nada'],
|
|
12099
|
+
["--prompt-overlay FILE", 'set: JSON {"edits":[{"what","find","replace","regex"?,"all"?}]}, aplicados en orden; cada uno debe encontrar su lugar o no cambia nada. {"edits":[]} = espejo exacto: un solo prompt y una sola memoria para los dos'],
|
|
12043
12100
|
["--prompt-patch FILE", 'set: el mismo formato {"edits":[\u2026]}, aplicado UNA vez sobre el prompt actual del agente en el servidor (no sobre una copia local: nunca pisa el cambio de alguien m\xE1s). Si una edici\xF3n no encuentra su lugar, no cambia nada. --dry-run imprime el diff'],
|
|
12044
12101
|
["--prompt-append FILE", "set: agrega ese texto al final del prompt (con --prompt-patch tambi\xE9n: primero las ediciones, luego el texto)"],
|
|
12045
12102
|
["--voice E:ID", "set: voz de las notas de voz: elevenlabs:<voiceId> o kokoro:em_santa|em_alex|ef_dora"],
|
|
@@ -12079,8 +12136,9 @@ var HELPS_ES = {
|
|
|
12079
12136
|
["--bubble-text T", "embed: etiqueta junto al bot\xF3n (\xAB\xBFDudas?\xBB)"],
|
|
12080
12137
|
["--auto-open S|off", "embed: se abre solo a los S segundos (1-120), una vez por visita, nunca en el tel\xE9fono"],
|
|
12081
12138
|
['--starters "a|b|c"', 'embed: hasta 4 sugerencias TUYAS ("" las quita; nunca salen las de Ghosty)'],
|
|
12082
|
-
["--style '{json}'|none", "embed: estilo fino, s\xF3lo llaves conocidas: fontFamily, radius, headerBg, headerText, titleUppercase, statusDot, headerAvatar, panelBg, userBubbleBg/Text, agentBubbleBg/Text, inputBg, sendBg, sendIcon, sendArrow (up|right), launcherBg, launcherIcon. PATCH por llave (null resetea una); none resetea todo"],
|
|
12139
|
+
["--style '{json}'|none", "embed: estilo fino, s\xF3lo llaves conocidas: fontFamily, radius, headerBg, headerText, titleUppercase, statusDot, headerAvatar, panelBg, userBubbleBg/Text, agentBubbleBg/Text, inputBg, sendBg, sendIcon, sendArrow (up|right), launcherBg, launcherIcon, typing (bounce|flow|flashing|shimmer), typingColor. PATCH por llave (null resetea una); none resetea todo"],
|
|
12083
12140
|
["--font NAME / --radius 0-24", "embed: atajos de style.fontFamily (lista de Google Fonts: Barlow, Inter, Poppins\u2026) y style.radius"],
|
|
12141
|
+
["--typing STYLE / --typing-color #rrggbb|none", "embed: el indicador de \xABescribiendo\xBB mientras responde: bounce (el de siempre), flow, flashing o shimmer (\xABPensando\u2026\xBB con brillo), y su color (por defecto, el de la marca)"],
|
|
12084
12142
|
["--theme-source custom|teams|site", "embed: importa el tema de la marca de tu espacio de Ghosty Teams (--workspace SLUG para elegir) o de tu sitio (--site-url); queda editable"],
|
|
12085
12143
|
["--site-url URL", "embed: el sitio del que se sacan los colores (implica --theme-source site)"],
|
|
12086
12144
|
["--style-file FILE", "embed: aplica un tema exportado con `agents embed <id> theme` (o s\xF3lo el objeto style)"],
|
|
@@ -12089,7 +12147,7 @@ var HELPS_ES = {
|
|
|
12089
12147
|
["--out FILE.tsx|.jsx [--force]", "embed: escribe en tu proyecto un componente de React COMPLETO y editable (sin depender de ning\xFAn paquete) con tu token y tu tema horneados arriba; no pisa un archivo que ya existe sin --force"],
|
|
12090
12148
|
["--check PATH", "box: este archivo debe existir en la m\xE1quina (repetible), p. ej. un archivo que trae la imagen nueva"],
|
|
12091
12149
|
["--contains PATH=TEXT", "box: ese archivo debe contener TEXT (un cambio que no agrega archivos)"],
|
|
12092
|
-
["--recycle", "box: reemplaza sus m\xE1quinas (nunca a media respuesta); pool: la nueva nace en el siguiente turno; ACP (goose, lite)
|
|
12150
|
+
["--recycle", "box: reemplaza sus m\xE1quinas (nunca a media respuesta); pool: la nueva nace en el siguiente turno; ACP (goose, lite) igual, con el historial del \xFAltimo respaldo"],
|
|
12093
12151
|
["--reenv / --force", "box --recycle en ACP: --reenv s\xF3lo re-hornea el env en la misma caja; --force la recrea aunque est\xE9 ocupada (due\xF1o o staff)"],
|
|
12094
12152
|
["--unset-env K1,K2", "set: borra esas variables del env (--env K= tambi\xE9n borra K)"],
|
|
12095
12153
|
["--tool [ch:]tool=on|off", "set: prende/apaga una tool en un canal (wa:actualizar_identidad=off) o en todos (crm_buscar=off); separadas por comas"],
|
|
@@ -12205,7 +12263,7 @@ var HELPS_ES = {
|
|
|
12205
12263
|
flags: [
|
|
12206
12264
|
["--media FILE", "chat: adjunta un archivo local (se repite)"],
|
|
12207
12265
|
["--file ID", "chat: adjunta de tus archivos (ghosty me files ls --q \u2026), separados por comas"],
|
|
12208
|
-
["--kind K", "archive|rm: test (pruebas)
|
|
12266
|
+
["--kind K", "archive|rm: test (pruebas), channel (clientes: s\xF3lo archivar, su memoria los sigue atendiendo) o personal (s\xF3lo TUS chats con ese agente; tambi\xE9n se van de tus apps)"],
|
|
12209
12267
|
["--before T", "archive|rm: s\xF3lo conversaciones sin mensajes desde T (7d, 12h o ISO)"],
|
|
12210
12268
|
["--user EMAIL", "ls/show (staff de Ghosty): las conversaciones de esa persona en cualquier agente; queda en bit\xE1cora"],
|
|
12211
12269
|
["--why", "show (staff de Ghosty): clase, de qui\xE9n es, qu\xE9 turno la fij\xF3, y si el due\xF1o / su usuario la ven en su lista o por liga"],
|
|
@@ -12265,6 +12323,7 @@ var HELPS_ES = {
|
|
|
12265
12323
|
["--text T / --sender N", "groups inject (staff): un mensaje que se perdi\xF3 (grupo apagado, deploy) entra como si N lo hubiera escrito ah\xED, y el agente contesta en el grupo"],
|
|
12266
12324
|
["--cached", "groups ls: no le pide a WhatsApp la lista en vivo (m\xE1s r\xE1pido; puede faltar alg\xFAn grupo nuevo)"],
|
|
12267
12325
|
["--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)"],
|
|
12326
|
+
["--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"],
|
|
12268
12327
|
["--list", "history --dry-run: CU\xC1LES conversaciones (tel\xE9fono, nombre, primer mensaje, mensajes, si vino de anuncio)"],
|
|
12269
12328
|
["--only-ads / --phones a,b", "history: importa (o lista) s\xF3lo las de anuncio y/o esos tel\xE9fonos"],
|
|
12270
12329
|
["--column NAME", "history: las tarjetas nuevas nacen en esa columna en vez de la primera"],
|
|
@@ -12566,7 +12625,7 @@ var HELPS = {
|
|
|
12566
12625
|
"ghosty agents embed enable|disable <agent-id> [--domains a.com,*.b.com] # web widget: chat bubble on your site, only on those domains",
|
|
12567
12626
|
"ghosty agents embed <agent-id> [--domains \u2026] [--per-visitor N] [--per-ip N] [--welcome TEXT] [--color #hex] [--rotate] # state + the <script> to paste",
|
|
12568
12627
|
'ghosty agents embed <agent-id> [--title T] [--subtitle T] [--avatar URL] [--icon chat|avatar|ghost] [--placeholder T] [--position right|left] [--offset X,Y] [--theme light|dark|auto] [--bubble-text T] [--auto-open S] [--starters "a|b"] # its look',
|
|
12569
|
-
"ghosty agents embed <agent-id> [--theme-source custom|teams|site] [--site-url URL] [--style '{json}'] [--style-file theme.json] [--font NAME] [--radius 0-24] # its theme",
|
|
12628
|
+
"ghosty agents embed <agent-id> [--theme-source custom|teams|site] [--site-url URL] [--style '{json}'] [--style-file theme.json] [--font NAME] [--radius 0-24] [--typing flow] [--typing-color #rrggbb] # its theme",
|
|
12570
12629
|
"ghosty agents embed <agent-id> [--copy '{json}'|none] [--copy-file texts.json] # what it says while it works",
|
|
12571
12630
|
"ghosty agents embed <agent-id> theme # export the theme as JSON (edit it, apply it back with --style-file)",
|
|
12572
12631
|
"ghosty agents embed <agent-id> --out src/components/GhostyChat.tsx [--force] # your own React component, token and theme baked in",
|
|
@@ -12584,7 +12643,7 @@ var HELPS = {
|
|
|
12584
12643
|
["--engine E --dry-run", "set: what changing the engine does (sessions forgotten, machine started and which one is destroyed, whether it is busy) without changing it; each conversation keeps its history"],
|
|
12585
12644
|
["--toolsets LIST", "set: gs tool groups it gets (crm, sales\u2026): a list replaces; +x / -x add or remove"],
|
|
12586
12645
|
["--prompt-base ID", "set: this agent's prompt = that agent's prompt + --prompt-overlay; regenerates when the base changes. none = unlink (keeps today's prompt)"],
|
|
12587
|
-
["--prompt-overlay FILE", 'set: JSON {"edits":[{"what","find","replace","regex"?,"all"?}]}, applied in order; each must find its place or nothing changes'],
|
|
12646
|
+
["--prompt-overlay FILE", 'set: JSON {"edits":[{"what","find","replace","regex"?,"all"?}]}, applied in order; each must find its place or nothing changes. {"edits":[]} = an exact mirror: one prompt and one memory for both agents'],
|
|
12588
12647
|
["--prompt-patch FILE", `set: the same {"edits":[\u2026]} format, applied ONCE on the agent's current prompt on the server (not a local copy: it never overwrites someone else's change). If one edit doesn't find its place, nothing changes. --dry-run prints the diff`],
|
|
12589
12648
|
["--prompt-append FILE", "set: add that text at the end of the prompt (with --prompt-patch too: edits first, then the text)"],
|
|
12590
12649
|
["--voice E:ID", "set: voice for voice notes: elevenlabs:<voiceId> or kokoro:em_santa|em_alex|ef_dora"],
|
|
@@ -12624,8 +12683,9 @@ var HELPS = {
|
|
|
12624
12683
|
["--bubble-text T", 'embed: label next to the button ("Questions?")'],
|
|
12625
12684
|
["--auto-open S|off", "embed: open by itself after S seconds (1-120), once per visit, never on phones"],
|
|
12626
12685
|
['--starters "a|b|c"', `embed: up to 4 of YOUR suggestions ("" removes them; Ghosty's are never shown)`],
|
|
12627
|
-
["--style '{json}'|none", "embed: fine style, only known keys: fontFamily, radius, headerBg, headerText, titleUppercase, statusDot, headerAvatar, panelBg, userBubbleBg/Text, agentBubbleBg/Text, inputBg, sendBg, sendIcon, sendArrow (up|right), launcherBg, launcherIcon. Patch per key (null resets one); none resets all"],
|
|
12686
|
+
["--style '{json}'|none", "embed: fine style, only known keys: fontFamily, radius, headerBg, headerText, titleUppercase, statusDot, headerAvatar, panelBg, userBubbleBg/Text, agentBubbleBg/Text, inputBg, sendBg, sendIcon, sendArrow (up|right), launcherBg, launcherIcon, typing (bounce|flow|flashing|shimmer), typingColor. Patch per key (null resets one); none resets all"],
|
|
12628
12687
|
["--font NAME / --radius 0-24", "embed: shortcuts for style.fontFamily (Google Fonts allow-list: Barlow, Inter, Poppins\u2026) and style.radius"],
|
|
12688
|
+
["--typing STYLE / --typing-color #rrggbb|none", 'embed: the "typing" indicator while the agent replies: bounce (default), flow, flashing or shimmer (glowing "Thinking\u2026" text), and its color (default: the brand color)'],
|
|
12629
12689
|
["--theme-source custom|teams|site", "embed: import the theme from the brand of your Ghosty Teams workspace (--workspace SLUG to pick one) or from your site (--site-url); it stays editable"],
|
|
12630
12690
|
["--site-url URL", "embed: the site to take colors from (implies --theme-source site)"],
|
|
12631
12691
|
["--style-file FILE", "embed: apply a theme exported with `agents embed <id> theme` (or a plain style object)"],
|
|
@@ -12634,7 +12694,7 @@ var HELPS = {
|
|
|
12634
12694
|
["--out FILE.tsx|.jsx [--force]", "embed: write a COMPLETE, editable React component into your project (no package needed) with your token and theme baked in at the top; won't overwrite an existing file without --force"],
|
|
12635
12695
|
["--check PATH", "box: this file must exist in the machine (repeatable), e.g. a file the new image brings"],
|
|
12636
12696
|
["--contains PATH=TEXT", "box: that file must contain TEXT (a change that adds no files)"],
|
|
12637
|
-
["--recycle", "box: replace its machines (not mid-turn); pool: the new one starts on the next turn; ACP (goose, lite)
|
|
12697
|
+
["--recycle", "box: replace its machines (not mid-turn); pool: the new one starts on the next turn; ACP (goose, lite) too, history from its last backup"],
|
|
12638
12698
|
["--reenv / --force", "box --recycle on ACP: --reenv only re-bakes the env in the same box; --force recreates it even if busy (owner or staff)"],
|
|
12639
12699
|
["--unset-env K1,K2", "set: delete these env variables (--env K= also deletes K)"],
|
|
12640
12700
|
["--tool [ch:]tool=on|off", "set: one tool on/off in one channel (wa:actualizar_identidad=off) or everywhere (crm_buscar=off); comma-separated"],
|
|
@@ -12837,7 +12897,7 @@ var HELPS = {
|
|
|
12837
12897
|
'ghosty chat <agent-id> ["message"] [--conversation ID] [--media FILE]\u2026 [--file ID[,ID\u2026]]',
|
|
12838
12898
|
"ghosty conversations ls <agent-id>",
|
|
12839
12899
|
"ghosty conversations show <agent-id> <conversation-id> [--limit 20]",
|
|
12840
|
-
"ghosty conversations archive|rm <agent-id> --kind test|channel [--before 7d] [--dry-run] [--yes]",
|
|
12900
|
+
"ghosty conversations archive|rm <agent-id> --kind test|channel|personal [--before 7d] [--dry-run] [--yes]",
|
|
12841
12901
|
"ghosty conversations ls --user <email> [--since 30d] [--surface android] # staff",
|
|
12842
12902
|
"ghosty conversations show <agent-id> <conversation-id> --why # staff: who sees it and why",
|
|
12843
12903
|
"ghosty conversations show <agent-id> <conversation-id> --tools # staff: what it ran and where it went"
|
|
@@ -12845,13 +12905,13 @@ var HELPS = {
|
|
|
12845
12905
|
flags: [
|
|
12846
12906
|
["--media FILE", "chat: attach a local file (repeatable)"],
|
|
12847
12907
|
["--file ID", "chat: attach from your files (ghosty me files ls --q \u2026), comma-separated"],
|
|
12848
|
-
["--kind K", "archive|rm: test (test chats)
|
|
12908
|
+
["--kind K", "archive|rm: test (test chats), channel (customers: archive only, their memory keeps serving them) or personal (only YOUR own chats with that agent; also gone from your apps)"],
|
|
12849
12909
|
["--before T", "archive|rm: only conversations with no message since T (7d, 12h or ISO)"],
|
|
12850
12910
|
["--user EMAIL", "ls/show (Ghosty staff): that person's conversations in any agent; logged"],
|
|
12851
12911
|
["--why", "show (Ghosty staff): kind, whose it is, which turn set it, and whether the owner / its user see it in their list or by link"],
|
|
12852
12912
|
["--tools", "show (Ghosty staff): every tool the agent ran with its command/args (secrets masked) and the external domains it named; never while a turn runs in that thread"]
|
|
12853
12913
|
],
|
|
12854
|
-
examples: ['ghosty chat <id> "hola"', "ghosty chat <id>", 'ghosty chat <id> "p\xE1salo a PDF" --media foto.jpg', "ghosty conversations rm <id> --kind test --before 7d --dry-run", "ghosty conversations archive <id> --kind channel --before 30d", "ghosty conversations ls --user david@empresa.com --since 7d"],
|
|
12914
|
+
examples: ['ghosty chat <id> "hola"', "ghosty chat <id>", 'ghosty chat <id> "p\xE1salo a PDF" --media foto.jpg', "ghosty conversations rm <id> --kind test --before 7d --dry-run", "ghosty conversations archive <id> --kind channel --before 30d", "ghosty conversations rm <id> --kind personal --dry-run", "ghosty conversations ls --user david@empresa.com --since 7d"],
|
|
12855
12915
|
learn: `${REF}#conversaciones`
|
|
12856
12916
|
},
|
|
12857
12917
|
schedule: {
|
|
@@ -12947,6 +13007,7 @@ HELPS.channels = {
|
|
|
12947
13007
|
["--text T / --sender N", "groups inject (staff): a message that got lost (group off, deploy) enters as if N wrote it there, and the agent answers in the group"],
|
|
12948
13008
|
["--cached", "groups ls: don't ask WhatsApp for the live list (faster; may miss new groups)"],
|
|
12949
13009
|
["--ads-only on|off", "link: only conversations that come from an ad open a card (also alone, to change it on a linked number)"],
|
|
13010
|
+
["--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"],
|
|
12950
13011
|
["--list", "history --dry-run: WHICH conversations (phone, name, first message, messages, from an ad)"],
|
|
12951
13012
|
["--only-ads / --phones a,b", "history: import (or list) only the ones from an ad and/or those phones"],
|
|
12952
13013
|
["--column NAME", "history: new cards are born in that column instead of the first one"],
|
|
@@ -14390,9 +14451,10 @@ async function supportThread(agent, sid, v) {
|
|
|
14390
14451
|
});
|
|
14391
14452
|
}
|
|
14392
14453
|
async function cleanupConversations(action, agent, v) {
|
|
14393
|
-
const ex = `ghosty conversations ${action} <agent> --kind ${action === "rm" ? "test" : "test|channel"} [--before 7d] [--dry-run]`;
|
|
14454
|
+
const ex = `ghosty conversations ${action} <agent> --kind ${action === "rm" ? "test|personal" : "test|channel|personal"} [--before 7d] [--dry-run]`;
|
|
14394
14455
|
if (!agent) throw usage(t("Missing agent.", "Falta el agente."), ex);
|
|
14395
|
-
if (v.kind !== "test" && v.kind !== "channel") throw usage(t("--kind takes test or
|
|
14456
|
+
if (v.kind !== "test" && v.kind !== "channel" && v.kind !== "personal") throw usage(t("--kind takes test, channel or personal.", "--kind acepta test, channel o personal."), ex);
|
|
14457
|
+
if (action === "rm" && v.kind === "channel") throw usage(t("Customer conversations (channel) are archived, never deleted: their memory keeps serving them.", "Los hilos de clientes (channel) se archivan, nunca se borran: su memoria los sigue atendiendo."), ex);
|
|
14396
14458
|
const path = `/api/v2/agents/${enc13(agent)}/conversations/cleanup`;
|
|
14397
14459
|
const body = { kind: v.kind, action, ...v.before ? { before: v.before } : {} };
|
|
14398
14460
|
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
@@ -14623,7 +14685,7 @@ ${bold("Agents")}
|
|
|
14623
14685
|
agents demo <id> Public demo link /p/<slug>: anyone tries it without an account, "Keep it" clones it to theirs
|
|
14624
14686
|
agents embed enable|disable <id> Web widget: a chat bubble on YOUR site (one <script>), only on the domains you list [--domains a.com,*.b.com] [--per-visitor N] [--per-ip N] [--welcome T] [--color #hex] [--rotate]
|
|
14625
14687
|
look: [--title T] [--subtitle T] [--avatar URL|none] [--icon chat|avatar|ghost] [--placeholder T] [--position right|left] [--offset X[,Y]]
|
|
14626
|
-
[--theme light|dark|auto] [--bubble-text T] [--auto-open SECONDS|off] [--starters "a|b|c"] [--font NAME] [--radius 0-24] [--style '{json}'|none]
|
|
14688
|
+
[--theme light|dark|auto] [--bubble-text T] [--auto-open SECONDS|off] [--starters "a|b|c"] [--font NAME] [--radius 0-24] [--typing bounce|flow|flashing|shimmer] [--typing-color #rrggbb|none] [--style '{json}'|none]
|
|
14627
14689
|
theme: [--theme-source custom|teams|site] [--workspace SLUG] [--site-url URL] [--style-file theme.json]
|
|
14628
14690
|
texts while it works: [--copy '{"waking":"One moment, please","thinking":["Reviewing your question\u2026"]}'|none] [--copy-file copy.json]
|
|
14629
14691
|
agents embed <id> theme Export the widget theme + texts as JSON (edit it and apply it back with --style-file)
|
|
@@ -14644,7 +14706,7 @@ ${bold("Configure an agent")}
|
|
|
14644
14706
|
channels whatsapp ls|enable|disable <id> [number] Which WhatsApp Business numbers it answers [--dry-run]
|
|
14645
14707
|
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]
|
|
14646
14708
|
channels messenger ls <id> The workspace's Messenger pages: who answers now and who answered last [--orphans]
|
|
14647
|
-
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] [--dry-run]
|
|
14709
|
+
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]
|
|
14648
14710
|
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]
|
|
14649
14711
|
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]
|
|
14650
14712
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
@@ -14684,7 +14746,7 @@ ${bold("Talk to an agent")}
|
|
|
14684
14746
|
chat <id> ["message"] Stream a conversation (no message = interactive) [--conversation ID] [--media FILE] [--file ID: from your files]
|
|
14685
14747
|
conversations ls <id> List conversations
|
|
14686
14748
|
conversations show <id> <conversation> What was said [--limit 20] (0 = all)
|
|
14687
|
-
conversations archive|rm <id> --kind test|channel Clean its history (rm:
|
|
14749
|
+
conversations archive|rm <id> --kind test|channel|personal Clean its history (rm: never customers) [--before 7d] [--dry-run]
|
|
14688
14750
|
turns ls <id> Recent turns and why they failed [--errors] [--skipped] [--since 1h] [--limit N]
|
|
14689
14751
|
turns ls --workspace SLUG --quota-hits Messages that got no turn because the balance ran out [--days 14]
|
|
14690
14752
|
turns show <id> [turn] What came in, what it answered, and where the time went (default: last) [--full]
|
|
@@ -14790,7 +14852,7 @@ ${bold("Agentes")}
|
|
|
14790
14852
|
agents demo <id> Liga p\xFAblica de demo /p/<slug>: cualquiera lo prueba sin cuenta y \xABQued\xE1rmelo\xBB lo clona a la suya
|
|
14791
14853
|
agents embed enable|disable <id> Widget web: burbuja de chat en TU sitio (un <script>), s\xF3lo en los dominios que pongas [--domains a.com,*.b.com] [--per-visitor N] [--per-ip N] [--welcome T] [--color #hex] [--rotate]
|
|
14792
14854
|
look: [--title T] [--subtitle T] [--avatar URL|none] [--icon chat|avatar|ghost] [--placeholder T] [--position right|left] [--offset X[,Y]]
|
|
14793
|
-
[--theme light|dark|auto] [--bubble-text T] [--auto-open SEGUNDOS|off] [--starters "a|b|c"] [--font NOMBRE] [--radius 0-24] [--style '{json}'|none]
|
|
14855
|
+
[--theme light|dark|auto] [--bubble-text T] [--auto-open SEGUNDOS|off] [--starters "a|b|c"] [--font NOMBRE] [--radius 0-24] [--typing bounce|flow|flashing|shimmer] [--typing-color #rrggbb|none] [--style '{json}'|none]
|
|
14794
14856
|
tema: [--theme-source custom|teams|site] [--workspace SLUG] [--site-url URL] [--style-file tema.json]
|
|
14795
14857
|
textos mientras trabaja: [--copy '{"waking":"Un momento, por favor","thinking":["Revisando su consulta\u2026"]}'|none] [--copy-file textos.json]
|
|
14796
14858
|
agents embed <id> theme Exporta el tema y los textos del widget en JSON (ed\xEDtalo y vuelve a aplicarlo con --style-file)
|
|
@@ -14811,7 +14873,7 @@ ${bold("Configurar un agente")}
|
|
|
14811
14873
|
channels whatsapp ls|enable|disable <id> [n\xFAmero] Qu\xE9 n\xFAmeros de WhatsApp Business contesta [--dry-run]
|
|
14812
14874
|
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]
|
|
14813
14875
|
channels messenger ls <id> Las p\xE1ginas de Messenger del espacio: qui\xE9n contesta hoy y qui\xE9n contest\xF3 al \xFAltimo [--orphans]
|
|
14814
|
-
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] [--dry-run]
|
|
14876
|
+
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]
|
|
14815
14877
|
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]
|
|
14816
14878
|
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]
|
|
14817
14879
|
channels wa pair <id> --phone N Vincula un WhatsApp personal con c\xF3digo (sin QR)
|
|
@@ -14851,7 +14913,7 @@ ${bold("Hablar con un agente")}
|
|
|
14851
14913
|
chat <id> ["mensaje"] Conversaci\xF3n en streaming (sin mensaje = interactivo) [--conversation ID] [--media ARCHIVO] [--file ID: de tus archivos]
|
|
14852
14914
|
conversations ls <id> Lista conversaciones
|
|
14853
14915
|
conversations show <id> <conversaci\xF3n> Qu\xE9 se dijo [--limit 20] (0 = todo)
|
|
14854
|
-
conversations archive|rm <id> --kind test|channel Limpia su historial (rm:
|
|
14916
|
+
conversations archive|rm <id> --kind test|channel|personal Limpia su historial (rm: nunca clientes) [--before 7d] [--dry-run]
|
|
14855
14917
|
turns ls <id> Turnos recientes y por qu\xE9 fallaron [--errors] [--skipped] [--since 1h] [--limit N]
|
|
14856
14918
|
turns ls --workspace SLUG --quota-hits Mensajes que no abrieron turno porque se acab\xF3 el saldo [--days 14]
|
|
14857
14919
|
turns show <id> [turno] Qu\xE9 lleg\xF3, qu\xE9 contest\xF3 y en qu\xE9 se fue el tiempo (default: el \xFAltimo) [--full]
|
|
@@ -14997,6 +15059,8 @@ async function main() {
|
|
|
14997
15059
|
style: { type: "string" },
|
|
14998
15060
|
font: { type: "string" },
|
|
14999
15061
|
radius: { type: "string" },
|
|
15062
|
+
typing: { type: "string" },
|
|
15063
|
+
"typing-color": { type: "string" },
|
|
15000
15064
|
"style-file": { type: "string" },
|
|
15001
15065
|
copy: { type: "string" },
|
|
15002
15066
|
"copy-file": { type: "string" },
|
|
@@ -15157,7 +15221,7 @@ async function main() {
|
|
|
15157
15221
|
const tokens = splitTokens(pos, v);
|
|
15158
15222
|
globals.token = tokens.session;
|
|
15159
15223
|
globals.profile = v.profile;
|
|
15160
|
-
if (v.version) return out({ version: "0.
|
|
15224
|
+
if (v.version) return out({ version: "0.58.1" }, () => "0.58.1");
|
|
15161
15225
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
15162
15226
|
const context = (await readConfig()).workspace;
|
|
15163
15227
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -15323,7 +15387,7 @@ async function main() {
|
|
|
15323
15387
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
15324
15388
|
}
|
|
15325
15389
|
}
|
|
15326
|
-
var notice = updateNotice("0.
|
|
15390
|
+
var notice = updateNotice("0.58.1").catch(() => null);
|
|
15327
15391
|
main().then(
|
|
15328
15392
|
async () => {
|
|
15329
15393
|
const n = await notice;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostystudio/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.58.1",
|
|
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": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "esbuild src/index.ts --bundle --platform=node --format=esm --target=node22 --outfile=dist/index.js --banner:js='#!/usr/bin/env node\nimport { createRequire as __cr } from \"node:module\"; const require = __cr(import.meta.url);' --define:__VERSION__=\\\"$npm_package_version\\\"",
|
|
18
18
|
"prepack": "npm run build",
|
|
19
|
-
"test": "for t in flags prompt api rows wa-auth resolve aliases i18n help completion photos channels-retry spaces sites diff cards; do esbuild src/$t.test.ts --bundle --platform=node --format=esm --outfile=/tmp/ghosty-cli-$t.test.mjs --log-level=error || exit 1; done && node --test /tmp/ghosty-cli-*.test.mjs"
|
|
19
|
+
"test": "for t in flags prompt api rows wa-auth resolve aliases i18n help completion photos channels-retry spaces sites diff cards env; do esbuild src/$t.test.ts --bundle --platform=node --format=esm --outfile=/tmp/ghosty-cli-$t.test.mjs --log-level=error || exit 1; done && node --test /tmp/ghosty-cli-*.test.mjs"
|
|
20
20
|
},
|
|
21
21
|
"keywords": [
|
|
22
22
|
"ghosty",
|