@ghostystudio/cli 0.58.0 → 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 +5 -1
- package/dist/index.js +87 -29
- 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`.
|
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.58.
|
|
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.58.
|
|
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);
|
|
@@ -10305,6 +10305,7 @@ ${bold("Partner space")} ${dim("(you, signed in as the space owner)")}
|
|
|
10305
10305
|
partner credentials rotate <keyId> [--grace MIN] New secret, same keyId (old one valid MIN, default 60)
|
|
10306
10306
|
partner credentials revoke <keyId> Revoke it (idempotent)
|
|
10307
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)
|
|
10308
10309
|
|
|
10309
10310
|
${bold("Shared agents (solo-MCP)")} ${dim("(--agent SLUG picks another agent of the partner: nik-admin, nik-public\u2026)")}
|
|
10310
10311
|
partner agent get [--agent SLUG] The agent template and its version
|
|
@@ -10350,6 +10351,7 @@ ${bold("Espacio de partner")} ${dim("(t\xFA, con sesi\xF3n como due\xF1a del es
|
|
|
10350
10351
|
partner credentials rotate <keyId> [--grace MIN] Secreto nuevo, mismo keyId (el viejo vale MIN, default 60)
|
|
10351
10352
|
partner credentials revoke <keyId> La revoca (idempotente)
|
|
10352
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)
|
|
10353
10355
|
|
|
10354
10356
|
${bold("Agentes compartidos (solo-MCP)")} ${dim("(--agent SLUG elige otro agente del partner: nik-admin, nik-public\u2026)")}
|
|
10355
10357
|
partner agent get [--agent SLUG] La plantilla del agente y su versi\xF3n
|
|
@@ -10406,7 +10408,7 @@ async function call(path, v, init = {}) {
|
|
|
10406
10408
|
"x-ghosty-ts": ts,
|
|
10407
10409
|
"x-ghosty-sig": sig,
|
|
10408
10410
|
"content-type": "application/json",
|
|
10409
|
-
"user-agent": `ghosty-cli/${"0.58.
|
|
10411
|
+
"user-agent": `ghosty-cli/${"0.58.1"}`
|
|
10410
10412
|
},
|
|
10411
10413
|
body: method === "GET" ? void 0 : raw
|
|
10412
10414
|
});
|
|
@@ -10649,6 +10651,29 @@ async function partnerCmd(sub, a1, a2, v, a3) {
|
|
|
10649
10651
|
const r = await json("/api/v2/partner/audit", v, { ownerOnly: true });
|
|
10650
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"]));
|
|
10651
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
|
+
}
|
|
10652
10677
|
case "try":
|
|
10653
10678
|
return tryCmd(a1, a2, v);
|
|
10654
10679
|
case "wa":
|
|
@@ -10986,7 +11011,7 @@ async function agentDocsCmd(sub, id, docs, v) {
|
|
|
10986
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"');
|
|
10987
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."));
|
|
10988
11013
|
const body = {
|
|
10989
|
-
...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) },
|
|
10990
11015
|
...v.url && v.name ? { name: v.name } : {},
|
|
10991
11016
|
...v.description ? { description: v.description } : {},
|
|
10992
11017
|
grant: v.grant === "no" ? false : v.grant === "write" || v.write ? "write" : "read",
|
|
@@ -11005,7 +11030,7 @@ async function agentDocsCmd(sub, id, docs, v) {
|
|
|
11005
11030
|
doc = need2(doc, t("document (id or exact name)", "el documento (id o nombre exacto)"), ex);
|
|
11006
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);
|
|
11007
11032
|
const body = {
|
|
11008
|
-
...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) },
|
|
11009
11034
|
...v.note ? { note: v.note } : {}
|
|
11010
11035
|
};
|
|
11011
11036
|
const r = await api(agentPath2(id, `/documents/${enc6(doc)}/versions`), { method: "POST", body });
|
|
@@ -11121,6 +11146,33 @@ async function turnsGrep(id, text, v) {
|
|
|
11121
11146
|
out(r, () => rows.length ? `${table(rows, ["at", "who", "turn", "state", "session", "text"])}
|
|
11122
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}` : ""}.`)));
|
|
11123
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
|
+
}
|
|
11124
11176
|
async function turnShow(id, turnId, full = false) {
|
|
11125
11177
|
id = need2(id, t("agent id", "el id del agente"), "ghosty turns show <agent-id> [turn-id|last] [--full]");
|
|
11126
11178
|
const r = await api(agentPath2(id, `/turns/${enc6(turnId ?? "last")}`));
|
|
@@ -11489,9 +11541,10 @@ async function channelsCmd(kind, sub, id, ref, v) {
|
|
|
11489
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)")),
|
|
11490
11542
|
"formmy forwards": fwd(n2),
|
|
11491
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")),
|
|
11492
11545
|
id: n2.id
|
|
11493
11546
|
}));
|
|
11494
|
-
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}`)));
|
|
11495
11548
|
}
|
|
11496
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");
|
|
11497
11550
|
if (!ref) throw usage(t("Missing number.", "Falta el n\xFAmero."), t("Example", "Ejemplo") + `: ghosty channels whatsapp ${sub} ${id} +52 55 1234 5678`);
|
|
@@ -11654,19 +11707,21 @@ async function linkCmd(sub, id, v) {
|
|
|
11654
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`);
|
|
11655
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."));
|
|
11656
11709
|
const adsOnly = v["ads-only"] === void 0 ? void 0 : v["ads-only"] === "on";
|
|
11657
|
-
|
|
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) {
|
|
11658
11713
|
const path2 = `/api/v2/agents/${enc7(id)}/whatsapp/link`;
|
|
11659
|
-
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 } : {} } });
|
|
11660
11715
|
return out(r2, () => `${r2.plan.map((x) => serverText(x)).join("\n")}${v["dry-run"] ? `
|
|
11661
|
-
${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}`))}` : ""}`);
|
|
11662
11717
|
}
|
|
11663
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)"));
|
|
11664
11719
|
const path = `/api/v2/agents/${enc7(id)}/whatsapp/link`;
|
|
11665
11720
|
if (v["partner-agent"] && !v["partner-tenant"]) throw usage(t("--partner-agent needs --partner-tenant <externalId>.", "--partner-agent necesita --partner-tenant <externalId>."));
|
|
11666
11721
|
const partner = v["partner-tenant"] ? { partnerExternalId: v["partner-tenant"], ...v["partner-agent"] ? { partnerAgentSlug: v["partner-agent"] } : {} } : {};
|
|
11667
|
-
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 } };
|
|
11668
11723
|
const partnerFlags = v["partner-tenant"] ? ` --partner-tenant ${v["partner-tenant"]}${v["partner-agent"] ? ` --partner-agent ${v["partner-agent"]}` : ""}` : "";
|
|
11669
|
-
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}` : ""}`;
|
|
11670
11725
|
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
11671
11726
|
const text = `${plan.plan.map((x) => serverText(x)).join("\n")}
|
|
11672
11727
|
${dim(`Formmy: ${plan.formmy.before.url ?? "null"} \u2192 ${plan.formmy.after.url ?? "null"} (${t("as", "como")} ${plan.formmy.by})`)}`;
|
|
@@ -12041,7 +12096,7 @@ var HELPS_ES = {
|
|
|
12041
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"],
|
|
12042
12097
|
["--toolsets LIST", "set: grupos de tools de gs que recibe (crm, sales\u2026): una lista reemplaza; +x / -x agrega o quita"],
|
|
12043
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)"],
|
|
12044
|
-
["--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'],
|
|
12045
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'],
|
|
12046
12101
|
["--prompt-append FILE", "set: agrega ese texto al final del prompt (con --prompt-patch tambi\xE9n: primero las ediciones, luego el texto)"],
|
|
12047
12102
|
["--voice E:ID", "set: voz de las notas de voz: elevenlabs:<voiceId> o kokoro:em_santa|em_alex|ef_dora"],
|
|
@@ -12092,7 +12147,7 @@ var HELPS_ES = {
|
|
|
12092
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"],
|
|
12093
12148
|
["--check PATH", "box: este archivo debe existir en la m\xE1quina (repetible), p. ej. un archivo que trae la imagen nueva"],
|
|
12094
12149
|
["--contains PATH=TEXT", "box: ese archivo debe contener TEXT (un cambio que no agrega archivos)"],
|
|
12095
|
-
["--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"],
|
|
12096
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)"],
|
|
12097
12152
|
["--unset-env K1,K2", "set: borra esas variables del env (--env K= tambi\xE9n borra K)"],
|
|
12098
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"],
|
|
@@ -12208,7 +12263,7 @@ var HELPS_ES = {
|
|
|
12208
12263
|
flags: [
|
|
12209
12264
|
["--media FILE", "chat: adjunta un archivo local (se repite)"],
|
|
12210
12265
|
["--file ID", "chat: adjunta de tus archivos (ghosty me files ls --q \u2026), separados por comas"],
|
|
12211
|
-
["--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)"],
|
|
12212
12267
|
["--before T", "archive|rm: s\xF3lo conversaciones sin mensajes desde T (7d, 12h o ISO)"],
|
|
12213
12268
|
["--user EMAIL", "ls/show (staff de Ghosty): las conversaciones de esa persona en cualquier agente; queda en bit\xE1cora"],
|
|
12214
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"],
|
|
@@ -12268,6 +12323,7 @@ var HELPS_ES = {
|
|
|
12268
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"],
|
|
12269
12324
|
["--cached", "groups ls: no le pide a WhatsApp la lista en vivo (m\xE1s r\xE1pido; puede faltar alg\xFAn grupo nuevo)"],
|
|
12270
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"],
|
|
12271
12327
|
["--list", "history --dry-run: CU\xC1LES conversaciones (tel\xE9fono, nombre, primer mensaje, mensajes, si vino de anuncio)"],
|
|
12272
12328
|
["--only-ads / --phones a,b", "history: importa (o lista) s\xF3lo las de anuncio y/o esos tel\xE9fonos"],
|
|
12273
12329
|
["--column NAME", "history: las tarjetas nuevas nacen en esa columna en vez de la primera"],
|
|
@@ -12587,7 +12643,7 @@ var HELPS = {
|
|
|
12587
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"],
|
|
12588
12644
|
["--toolsets LIST", "set: gs tool groups it gets (crm, sales\u2026): a list replaces; +x / -x add or remove"],
|
|
12589
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)"],
|
|
12590
|
-
["--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'],
|
|
12591
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`],
|
|
12592
12648
|
["--prompt-append FILE", "set: add that text at the end of the prompt (with --prompt-patch too: edits first, then the text)"],
|
|
12593
12649
|
["--voice E:ID", "set: voice for voice notes: elevenlabs:<voiceId> or kokoro:em_santa|em_alex|ef_dora"],
|
|
@@ -12638,7 +12694,7 @@ var HELPS = {
|
|
|
12638
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"],
|
|
12639
12695
|
["--check PATH", "box: this file must exist in the machine (repeatable), e.g. a file the new image brings"],
|
|
12640
12696
|
["--contains PATH=TEXT", "box: that file must contain TEXT (a change that adds no files)"],
|
|
12641
|
-
["--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"],
|
|
12642
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)"],
|
|
12643
12699
|
["--unset-env K1,K2", "set: delete these env variables (--env K= also deletes K)"],
|
|
12644
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"],
|
|
@@ -12841,7 +12897,7 @@ var HELPS = {
|
|
|
12841
12897
|
'ghosty chat <agent-id> ["message"] [--conversation ID] [--media FILE]\u2026 [--file ID[,ID\u2026]]',
|
|
12842
12898
|
"ghosty conversations ls <agent-id>",
|
|
12843
12899
|
"ghosty conversations show <agent-id> <conversation-id> [--limit 20]",
|
|
12844
|
-
"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]",
|
|
12845
12901
|
"ghosty conversations ls --user <email> [--since 30d] [--surface android] # staff",
|
|
12846
12902
|
"ghosty conversations show <agent-id> <conversation-id> --why # staff: who sees it and why",
|
|
12847
12903
|
"ghosty conversations show <agent-id> <conversation-id> --tools # staff: what it ran and where it went"
|
|
@@ -12849,13 +12905,13 @@ var HELPS = {
|
|
|
12849
12905
|
flags: [
|
|
12850
12906
|
["--media FILE", "chat: attach a local file (repeatable)"],
|
|
12851
12907
|
["--file ID", "chat: attach from your files (ghosty me files ls --q \u2026), comma-separated"],
|
|
12852
|
-
["--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)"],
|
|
12853
12909
|
["--before T", "archive|rm: only conversations with no message since T (7d, 12h or ISO)"],
|
|
12854
12910
|
["--user EMAIL", "ls/show (Ghosty staff): that person's conversations in any agent; logged"],
|
|
12855
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"],
|
|
12856
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"]
|
|
12857
12913
|
],
|
|
12858
|
-
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"],
|
|
12859
12915
|
learn: `${REF}#conversaciones`
|
|
12860
12916
|
},
|
|
12861
12917
|
schedule: {
|
|
@@ -12951,6 +13007,7 @@ HELPS.channels = {
|
|
|
12951
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"],
|
|
12952
13008
|
["--cached", "groups ls: don't ask WhatsApp for the live list (faster; may miss new groups)"],
|
|
12953
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"],
|
|
12954
13011
|
["--list", "history --dry-run: WHICH conversations (phone, name, first message, messages, from an ad)"],
|
|
12955
13012
|
["--only-ads / --phones a,b", "history: import (or list) only the ones from an ad and/or those phones"],
|
|
12956
13013
|
["--column NAME", "history: new cards are born in that column instead of the first one"],
|
|
@@ -14394,9 +14451,10 @@ async function supportThread(agent, sid, v) {
|
|
|
14394
14451
|
});
|
|
14395
14452
|
}
|
|
14396
14453
|
async function cleanupConversations(action, agent, v) {
|
|
14397
|
-
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]`;
|
|
14398
14455
|
if (!agent) throw usage(t("Missing agent.", "Falta el agente."), ex);
|
|
14399
|
-
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);
|
|
14400
14458
|
const path = `/api/v2/agents/${enc13(agent)}/conversations/cleanup`;
|
|
14401
14459
|
const body = { kind: v.kind, action, ...v.before ? { before: v.before } : {} };
|
|
14402
14460
|
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
@@ -14648,7 +14706,7 @@ ${bold("Configure an agent")}
|
|
|
14648
14706
|
channels whatsapp ls|enable|disable <id> [number] Which WhatsApp Business numbers it answers [--dry-run]
|
|
14649
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]
|
|
14650
14708
|
channels messenger ls <id> The workspace's Messenger pages: who answers now and who answered last [--orphans]
|
|
14651
|
-
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]
|
|
14652
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]
|
|
14653
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]
|
|
14654
14712
|
channels wa pair <id> --phone N Pair a personal WhatsApp by code (no QR)
|
|
@@ -14688,7 +14746,7 @@ ${bold("Talk to an agent")}
|
|
|
14688
14746
|
chat <id> ["message"] Stream a conversation (no message = interactive) [--conversation ID] [--media FILE] [--file ID: from your files]
|
|
14689
14747
|
conversations ls <id> List conversations
|
|
14690
14748
|
conversations show <id> <conversation> What was said [--limit 20] (0 = all)
|
|
14691
|
-
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]
|
|
14692
14750
|
turns ls <id> Recent turns and why they failed [--errors] [--skipped] [--since 1h] [--limit N]
|
|
14693
14751
|
turns ls --workspace SLUG --quota-hits Messages that got no turn because the balance ran out [--days 14]
|
|
14694
14752
|
turns show <id> [turn] What came in, what it answered, and where the time went (default: last) [--full]
|
|
@@ -14815,7 +14873,7 @@ ${bold("Configurar un agente")}
|
|
|
14815
14873
|
channels whatsapp ls|enable|disable <id> [n\xFAmero] Qu\xE9 n\xFAmeros de WhatsApp Business contesta [--dry-run]
|
|
14816
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]
|
|
14817
14875
|
channels messenger ls <id> Las p\xE1ginas de Messenger del espacio: qui\xE9n contesta hoy y qui\xE9n contest\xF3 al \xFAltimo [--orphans]
|
|
14818
|
-
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]
|
|
14819
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]
|
|
14820
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]
|
|
14821
14879
|
channels wa pair <id> --phone N Vincula un WhatsApp personal con c\xF3digo (sin QR)
|
|
@@ -14855,7 +14913,7 @@ ${bold("Hablar con un agente")}
|
|
|
14855
14913
|
chat <id> ["mensaje"] Conversaci\xF3n en streaming (sin mensaje = interactivo) [--conversation ID] [--media ARCHIVO] [--file ID: de tus archivos]
|
|
14856
14914
|
conversations ls <id> Lista conversaciones
|
|
14857
14915
|
conversations show <id> <conversaci\xF3n> Qu\xE9 se dijo [--limit 20] (0 = todo)
|
|
14858
|
-
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]
|
|
14859
14917
|
turns ls <id> Turnos recientes y por qu\xE9 fallaron [--errors] [--skipped] [--since 1h] [--limit N]
|
|
14860
14918
|
turns ls --workspace SLUG --quota-hits Mensajes que no abrieron turno porque se acab\xF3 el saldo [--days 14]
|
|
14861
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]
|
|
@@ -15163,7 +15221,7 @@ async function main() {
|
|
|
15163
15221
|
const tokens = splitTokens(pos, v);
|
|
15164
15222
|
globals.token = tokens.session;
|
|
15165
15223
|
globals.profile = v.profile;
|
|
15166
|
-
if (v.version) return out({ version: "0.58.
|
|
15224
|
+
if (v.version) return out({ version: "0.58.1" }, () => "0.58.1");
|
|
15167
15225
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
15168
15226
|
const context = (await readConfig()).workspace;
|
|
15169
15227
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -15329,7 +15387,7 @@ async function main() {
|
|
|
15329
15387
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
15330
15388
|
}
|
|
15331
15389
|
}
|
|
15332
|
-
var notice = updateNotice("0.58.
|
|
15390
|
+
var notice = updateNotice("0.58.1").catch(() => null);
|
|
15333
15391
|
main().then(
|
|
15334
15392
|
async () => {
|
|
15335
15393
|
const n = await notice;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostystudio/cli",
|
|
3
|
-
"version": "0.58.
|
|
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",
|