@ghostystudio/cli 0.45.0 → 0.47.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 +9 -0
- package/dist/index.js +143 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,6 +103,15 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
|
|
|
103
103
|
|
|
104
104
|
Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
105
105
|
|
|
106
|
+
### Changes in 0.47.0
|
|
107
|
+
|
|
108
|
+
- `agents set --quote` takes VAT rules for the house `cotizar` tool: `iva-incluido=true` (prices already include VAT), `iva.CATEGORY=16` (VAT for that category), `solo-factura=true` (VAT only when the customer asks for an invoice).
|
|
109
|
+
- New `agents set --catalog products.csv|json`: the house `cotizar` tool's catalog (sku, nombre, precio, unidad, categoria). The category comes from here, not from the model.
|
|
110
|
+
|
|
111
|
+
### Changes in 0.46.0
|
|
112
|
+
|
|
113
|
+
- New `staff ls|assign|unassign <staff-email> <client-email>` (Ghosty staff): a staff member assigned to a client account sees and runs its agents (with or without a workspace), documents, databases and boards as themselves — no keys, billing or transfers, every write logged. The client sees «Your Ghosty account manager».
|
|
114
|
+
|
|
106
115
|
### Changes in 0.45.0
|
|
107
116
|
|
|
108
117
|
- New `turns grep <id> "text" [--since 7d] [--role user|agent]`: finds what the customer or the agent said, with its turn, to open with `turns show`.
|
package/dist/index.js
CHANGED
|
@@ -3122,9 +3122,9 @@ var require_timestamp = __commonJS({
|
|
|
3122
3122
|
const match = str.match(timestamp.test);
|
|
3123
3123
|
if (!match)
|
|
3124
3124
|
throw new Error("!!timestamp expects a date, starting with yyyy-mm-dd");
|
|
3125
|
-
const [, year, month,
|
|
3125
|
+
const [, year, month, day3, hour, minute, second] = match.map(Number);
|
|
3126
3126
|
const millisec = match[7] ? Number((match[7] + "00").substr(1, 3)) : 0;
|
|
3127
|
-
let date = Date.UTC(year, month - 1,
|
|
3127
|
+
let date = Date.UTC(year, month - 1, day3, hour || 0, minute || 0, second || 0, millisec);
|
|
3128
3128
|
const tz = match[8];
|
|
3129
3129
|
if (tz && tz !== "Z") {
|
|
3130
3130
|
let d = parseSexagesimal(tz, false);
|
|
@@ -8422,7 +8422,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
|
|
|
8422
8422
|
const req = httpsRequest(`${base}${path}`, {
|
|
8423
8423
|
method: "POST",
|
|
8424
8424
|
timeout: timeoutMs,
|
|
8425
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
8425
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.47.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
8426
8426
|
}, (res) => {
|
|
8427
8427
|
let buf = "";
|
|
8428
8428
|
res.on("data", (c) => buf += c);
|
|
@@ -8464,7 +8464,7 @@ async function request(path, opts = {}, retried = false) {
|
|
|
8464
8464
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
8465
8465
|
headers: {
|
|
8466
8466
|
authorization: `Bearer ${token}`,
|
|
8467
|
-
"user-agent": `ghosty-cli/${"0.
|
|
8467
|
+
"user-agent": `ghosty-cli/${"0.47.0"}`,
|
|
8468
8468
|
"accept-language": lang(),
|
|
8469
8469
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
8470
8470
|
...opts.headers
|
|
@@ -8764,6 +8764,36 @@ async function agentsGet(id, fields, promptOut) {
|
|
|
8764
8764
|
const q = fields ? `?fields=${enc2(fields)}` : "?full=1";
|
|
8765
8765
|
out(await api(agentPath(id, q)));
|
|
8766
8766
|
}
|
|
8767
|
+
function parseCsv(text) {
|
|
8768
|
+
const rows = [];
|
|
8769
|
+
let row = [], cell = "", q = false;
|
|
8770
|
+
for (let i = 0; i < text.length; i++) {
|
|
8771
|
+
const c = text[i];
|
|
8772
|
+
if (q) {
|
|
8773
|
+
if (c === '"' && text[i + 1] === '"') {
|
|
8774
|
+
cell += '"';
|
|
8775
|
+
i++;
|
|
8776
|
+
} else if (c === '"') q = false;
|
|
8777
|
+
else cell += c;
|
|
8778
|
+
} else if (c === '"') q = true;
|
|
8779
|
+
else if (c === ",") {
|
|
8780
|
+
row.push(cell);
|
|
8781
|
+
cell = "";
|
|
8782
|
+
} else if (c === "\n" || c === "\r") {
|
|
8783
|
+
if (c === "\r" && text[i + 1] === "\n") i++;
|
|
8784
|
+
row.push(cell);
|
|
8785
|
+
cell = "";
|
|
8786
|
+
if (row.some((x) => x.trim())) rows.push(row);
|
|
8787
|
+
row = [];
|
|
8788
|
+
} else cell += c;
|
|
8789
|
+
}
|
|
8790
|
+
row.push(cell);
|
|
8791
|
+
if (row.some((x) => x.trim())) rows.push(row);
|
|
8792
|
+
const [head, ...body] = rows;
|
|
8793
|
+
if (!head) return [];
|
|
8794
|
+
const keys = head.map((h) => h.trim().toLowerCase());
|
|
8795
|
+
return body.map((r) => Object.fromEntries(keys.map((k, i) => [k, k === "precio" ? Number((r[i] ?? "").replace(/[$,\s]/g, "")) : (r[i] ?? "").trim()])));
|
|
8796
|
+
}
|
|
8767
8797
|
async function agentsSet(id, v) {
|
|
8768
8798
|
id = need(id, "agent id", "ghosty agents set <agent-id> --prompt-file PROMPT.md");
|
|
8769
8799
|
const done = [];
|
|
@@ -8864,19 +8894,32 @@ ${dim(t("Dry run: nothing changed.", "Simulacro: no se cambi\xF3 nada."))}`);
|
|
|
8864
8894
|
body.autoStage = v["auto-stage"] === "on";
|
|
8865
8895
|
}
|
|
8866
8896
|
if (v.quote) {
|
|
8867
|
-
const alias = { iva: "ivaPct", vigencia: "vigenciaDias", prefix: "folioPrefijo", prefijo: "folioPrefijo", currency: "moneda", company: "empresa", phone: "telefono", email: "correo", address: "direccion", notes: "notas" };
|
|
8897
|
+
const alias = { iva: "ivaPct", vigencia: "vigenciaDias", prefix: "folioPrefijo", prefijo: "folioPrefijo", currency: "moneda", company: "empresa", phone: "telefono", email: "correo", address: "direccion", notes: "notas", "iva-incluido": "ivaIncluido", "solo-factura": "ivaSoloConFactura" };
|
|
8868
8898
|
const cot = {};
|
|
8869
|
-
|
|
8870
|
-
|
|
8899
|
+
let cats = null;
|
|
8900
|
+
for (const part of v.quote.split(/,(?=\s*[a-zA-Z-]+(?:\.[^=,]+)?=)/)) {
|
|
8901
|
+
const m = /^\s*([a-zA-Z-]+)(?:\.([^=]+))?=(.*)$/.exec(part);
|
|
8871
8902
|
if (!m) throw usage(t(`Bad --quote: ${part}.`, `--quote inv\xE1lido: ${part}.`), "--quote iva=0,prefix=SFI,vigencia=15");
|
|
8872
|
-
const
|
|
8873
|
-
const val =
|
|
8874
|
-
|
|
8903
|
+
const [, rawKey, category, rawVal] = m;
|
|
8904
|
+
const val = rawVal.trim().replace(/^"(.*)"$/, "$1");
|
|
8905
|
+
if (rawKey.toLowerCase() === "iva" && category) {
|
|
8906
|
+
if (!cats) cats = { ...(await api(agentPath(id, "?fields=cotizacion"))).cotizacion?.ivaPorCategoria ?? {} };
|
|
8907
|
+
if (val === "") delete cats[category];
|
|
8908
|
+
else cats[category] = Number(val);
|
|
8909
|
+
continue;
|
|
8910
|
+
}
|
|
8911
|
+
const key = alias[rawKey] ?? rawKey;
|
|
8912
|
+
cot[key] = key === "ivaPct" || key === "vigenciaDias" ? Number(val) : key === "ivaIncluido" || key === "ivaSoloConFactura" ? /^(true|on|yes|si|sí|1)$/i.test(val) : val;
|
|
8875
8913
|
}
|
|
8914
|
+
if (cats) cot.ivaPorCategoria = cats;
|
|
8876
8915
|
body.cotizacion = cot;
|
|
8877
8916
|
}
|
|
8917
|
+
if (v.catalog) {
|
|
8918
|
+
const raw = await readFile3(resolve(v.catalog), "utf8");
|
|
8919
|
+
body.catalogo = v.catalog.toLowerCase().endsWith(".json") ? JSON.parse(raw) : parseCsv(raw);
|
|
8920
|
+
}
|
|
8878
8921
|
if (!Object.keys(body).length && done.length) return out({ id, updated: done }, () => `${lavender("\u2713")} ${t("Updated", "Actualizado")}: ${done.join(" \xB7 ")}`);
|
|
8879
|
-
if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), t("Use", "Usa") + " --name, --engine, --model, --prompt, --prompt-file, --env, --unset-env, --channels, --toolsets, --tool, --connect, --disconnect, --voice, --voice-replies, --auto-stage, --quote, --bag " + t("or", "o") + " --avatar.");
|
|
8922
|
+
if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), t("Use", "Usa") + " --name, --engine, --model, --prompt, --prompt-file, --env, --unset-env, --channels, --toolsets, --tool, --connect, --disconnect, --voice, --voice-replies, --auto-stage, --quote, --catalog, --bag " + t("or", "o") + " --avatar.");
|
|
8880
8923
|
const r = await api(agentPath(id), { method: "PATCH", body });
|
|
8881
8924
|
out(r, () => `${lavender("\u2713")} ${t("Updated", "Actualizado")}: ${[...Object.keys(body), ...done].join(", ")}.`);
|
|
8882
8925
|
}
|
|
@@ -9738,7 +9781,7 @@ async function call(path, v, init = {}) {
|
|
|
9738
9781
|
"x-ghosty-ts": ts,
|
|
9739
9782
|
"x-ghosty-sig": sig,
|
|
9740
9783
|
"content-type": "application/json",
|
|
9741
|
-
"user-agent": `ghosty-cli/${"0.
|
|
9784
|
+
"user-agent": `ghosty-cli/${"0.47.0"}`
|
|
9742
9785
|
},
|
|
9743
9786
|
body: method === "GET" ? void 0 : raw
|
|
9744
9787
|
});
|
|
@@ -11225,7 +11268,8 @@ var HELPS_ES = {
|
|
|
11225
11268
|
["--voice E:ID", "set: voz de las notas de voz: elevenlabs:<voiceId> o kokoro:em_santa|em_alex|ef_dora"],
|
|
11226
11269
|
["--voice-replies M", "set: auto = contesta con nota de voz cuando el cliente manda o pide audio; off = siempre texto"],
|
|
11227
11270
|
["--auto-stage on|off", "set: mueve solo las tarjetas del tablero tras cada turno del cliente (una llamada extra al modelo por turno)"],
|
|
11228
|
-
["--quote k=v,\u2026", "set: config de la tool de casa `cotizar` \u2014 iva (0-100), vigencia (d\xEDas), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Vac\xEDo lo borra (rfc=). El contador de folio no se toca"],
|
|
11271
|
+
["--quote k=v,\u2026", "set: config de la tool de casa `cotizar` \u2014 iva (0-100), iva-incluido=true (los precios del cat\xE1logo ya traen IVA), iva.CATEGORIA=16 (IVA de esa categor\xEDa del cat\xE1logo; iva.CATEGORIA= la quita), solo-factura=true (IVA s\xF3lo si el cliente pide factura), vigencia (d\xEDas), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Vac\xEDo lo borra (rfc=). El contador de folio no se toca"],
|
|
11272
|
+
["--catalog ARCHIVO", "set: el cat\xE1logo de la tool de casa `cotizar` desde un CSV (sku,nombre,precio[,unidad,categoria,descripcion]) o una lista JSON; reemplaza al anterior. Su `categoria` decide las reglas de IVA"],
|
|
11229
11273
|
["--verbose", "doctor: lista tambi\xE9n las revisiones que pasaron"],
|
|
11230
11274
|
["--user EMAIL", "doctor (staff de Ghosty): los agentes de esa persona \u2014 doctor, \xFAltimos turnos (estado, segundos, error y \xABfetched\xBB: si su app pidi\xF3 el hilo despu\xE9s de que termin\xF3 el turno), plan/bolsa y cajas (marca duplicadas); queda en bit\xE1cora"],
|
|
11231
11275
|
["--turns N", "doctor --user: cu\xE1ntos turnos recientes por agente (default 8, m\xE1x. 50)"],
|
|
@@ -11598,6 +11642,18 @@ var HELPS_ES = {
|
|
|
11598
11642
|
["--yes", "s\xE1ltate la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
11599
11643
|
],
|
|
11600
11644
|
notes: ["create sigue las reglas de la web: queda a tu nombre, nace como prueba de 30 d\xEDas, tu correo debe estar confirmado y tu plan topa cu\xE1ntos tienes. Sigue: ghosty partner enable <slug>.", "Con suscripci\xF3n de Stripe renew se niega: la fecha la mueve la factura pagada.", "rename cambia s\xF3lo el slug (id y namespace se quedan, as\xED que tablero, Stripe y WhatsApp siguen funcionando); las ligas viejas <slug>.sales dejan de servir.", "transfer se lleva los agentes con el espacio y recicla sus cajas (el due\xF1o va horneado en la caja); sin --copy-keys la simulaci\xF3n dice qu\xE9 llaves le faltan al nuevo \u2014 esos agentes dejar\xEDan de contestar."]
|
|
11645
|
+
},
|
|
11646
|
+
staff: {
|
|
11647
|
+
summary: "Staff de Ghosty asignado a CUENTAS cliente (admin delegado que act\xFAa como s\xED mismo): ve y opera con su propia sesi\xF3n los agentes (con y sin espacio), documentos, bases y tableros de esa cuenta. Sin llaves, cobro, traspasos ni borrados. S\xF3lo el staff de Ghosty asigna; el cliente s\xF3lo ve \xABTu ejecutivo de Ghosty\xBB. Cada cambio y cada escritura quedan en la bit\xE1cora.",
|
|
11648
|
+
flags: [
|
|
11649
|
+
["--all", "ls: tambi\xE9n las asignaciones revocadas"],
|
|
11650
|
+
["--reason TEXT", "assign: por qu\xE9 (va a la bit\xE1cora)"],
|
|
11651
|
+
["--yes", "unassign: s\xE1ltate la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
11652
|
+
],
|
|
11653
|
+
notes: [
|
|
11654
|
+
"En el panel web el staff elige \xABAtendiendo: <cliente>\xBB (Documentos y bases, Agentes); es una cookie que se revalida en cada request, nunca otra sesi\xF3n.",
|
|
11655
|
+
"Revocar corta en el siguiente request. Asignar dos veces no hace nada (una sola activa por par)."
|
|
11656
|
+
]
|
|
11601
11657
|
}
|
|
11602
11658
|
};
|
|
11603
11659
|
var HELP_ALIASES = { creds: "credentials", conectores: "connectors", board: "cards", conversations: "chat", workspaces: "spaces" };
|
|
@@ -11652,7 +11708,8 @@ var HELPS = {
|
|
|
11652
11708
|
["--voice E:ID", "set: voice for voice notes: elevenlabs:<voiceId> or kokoro:em_santa|em_alex|ef_dora"],
|
|
11653
11709
|
["--voice-replies M", "set: auto = answer with a voice note when the customer sends or asks for audio; off = always text"],
|
|
11654
11710
|
["--auto-stage on|off", "set: move board cards by itself after each customer turn (one extra model call per turn)"],
|
|
11655
|
-
["--quote k=v,\u2026", "set: config of the house `cotizar` tool \u2014 iva (0-100), vigencia (days), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Empty value clears it (rfc=). The folio counter is never touched"],
|
|
11711
|
+
["--quote k=v,\u2026", "set: config of the house `cotizar` tool \u2014 iva (0-100), iva-incluido=true (catalog prices already include VAT), iva.CATEGORY=16 (VAT for that catalog category; iva.CATEGORY= removes it), solo-factura=true (VAT only when the customer asks for an invoice), vigencia (days), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Empty value clears it (rfc=). The folio counter is never touched"],
|
|
11712
|
+
["--catalog FILE", "set: the house `cotizar` tool's catalog from a CSV (sku,nombre,precio[,unidad,categoria,descripcion]) or JSON list; replaces the previous one. Its `categoria` drives the VAT rules"],
|
|
11656
11713
|
["--verbose", "doctor: also list the checks that passed"],
|
|
11657
11714
|
["--user EMAIL", "doctor (Ghosty staff): that person's agents \u2014 doctor, latest turns (state, seconds, error, and \xABfetched\xBB: whether their app asked for the thread after the turn ended), plan/bag and boxes (duplicates flagged); logged"],
|
|
11658
11715
|
["--turns N", "doctor --user: how many recent turns per agent (default 8, max 50)"],
|
|
@@ -12229,6 +12286,25 @@ HELPS.sites = {
|
|
|
12229
12286
|
notes: ["A folder needs index.html at its root; hidden files and node_modules are skipped. Limits: 1 MB per file, 8 MB and 40 files per site.", "Without --site, publish always creates a new site (house sites are never matched by title).", "Slug errors: slug_invalid, slug_taken, and slug_unsupported while EasyBits does not accept a slug yet (exit 1, nothing changes)."],
|
|
12230
12287
|
learn: `${REF}#sitios`
|
|
12231
12288
|
};
|
|
12289
|
+
HELPS.staff = {
|
|
12290
|
+
summary: "Ghosty staff assigned to client ACCOUNTS (delegated admin acting as themselves): the staff member sees and runs that account's agents (with and without a workspace), documents, databases and boards with their own session. No keys, billing, transfers or deletes. Only Ghosty staff assigns; the customer just sees \xABYour Ghosty account executive\xBB. Every change and every write is logged.",
|
|
12291
|
+
usage: [
|
|
12292
|
+
"ghosty staff ls [staff-email] [client-email] [--all]",
|
|
12293
|
+
"ghosty staff assign <staff-email> <client-email> [--reason TEXT]",
|
|
12294
|
+
"ghosty staff unassign <staff-email> <client-email> [--yes]"
|
|
12295
|
+
],
|
|
12296
|
+
flags: [
|
|
12297
|
+
["--all", "ls: also revoked assignments"],
|
|
12298
|
+
["--reason TEXT", "assign: why (goes to the audit log)"],
|
|
12299
|
+
["--yes", "unassign: skip the confirmation (required without a terminal)"]
|
|
12300
|
+
],
|
|
12301
|
+
examples: ['ghosty staff assign brenda@siiqtec.com siiqtec@gmail.com --reason "migraci\xF3n SIIQTEC"', "ghosty staff ls brenda@siiqtec.com", "ghosty staff unassign brenda@siiqtec.com siiqtec@gmail.com --yes"],
|
|
12302
|
+
notes: [
|
|
12303
|
+
"In the web panel the staff member picks \xABAtendiendo: <client>\xBB (Documents and databases, Agents); it is a cookie revalidated on every request, never another session.",
|
|
12304
|
+
"Revoking cuts on the next request. Assigning twice is a no-op (one active assignment per pair)."
|
|
12305
|
+
],
|
|
12306
|
+
learn: `${REF}#staff-asignado`
|
|
12307
|
+
};
|
|
12232
12308
|
function helpText(cmd) {
|
|
12233
12309
|
const base = HELPS[cmd];
|
|
12234
12310
|
if (!base) return void 0;
|
|
@@ -12843,7 +12919,7 @@ ${dim(t(`${total2} message(s) unanswered for lack of balance in ${r.days} day(s)
|
|
|
12843
12919
|
d.noQuota += x.noQuota;
|
|
12844
12920
|
days.set(x.day, d);
|
|
12845
12921
|
}
|
|
12846
|
-
rows = [...days].map(([
|
|
12922
|
+
rows = [...days].map(([day3, x]) => ({ day: day3, ...fmt2(x) }));
|
|
12847
12923
|
} else rows = r.agents.map((x) => ({ agent: x.agent, ...fmt2(x) }));
|
|
12848
12924
|
const cols = [...by.has("day") ? ["day"] : [], ...by.has("agent") ? ["agent"] : [], "turns", "failed", "tokens", "no balance"];
|
|
12849
12925
|
const total = r.agents.reduce((n, a) => n + a.billable, 0);
|
|
@@ -13044,6 +13120,43 @@ ${dim(t("Links with the old slug may stop working.", "Las ligas con el slug viej
|
|
|
13044
13120
|
}
|
|
13045
13121
|
}
|
|
13046
13122
|
|
|
13123
|
+
// src/commands/staff.ts
|
|
13124
|
+
var day2 = (iso) => iso ? iso.slice(0, 10) : "";
|
|
13125
|
+
async function staffCmd(sub, staff, client, v) {
|
|
13126
|
+
if (!sub || sub === "ls" || sub === "list") {
|
|
13127
|
+
const q = new URLSearchParams();
|
|
13128
|
+
if (staff) q.set("staff", staff);
|
|
13129
|
+
if (client) q.set("client", client);
|
|
13130
|
+
if (v.all) q.set("all", "1");
|
|
13131
|
+
const r = await api(`/api/v2/staff/assignments${q.toString() ? `?${q}` : ""}`);
|
|
13132
|
+
const rows = r.assignments.map((a) => ({
|
|
13133
|
+
staff: a.staff.email,
|
|
13134
|
+
client: a.client.email,
|
|
13135
|
+
since: day2(a.createdAt),
|
|
13136
|
+
by: a.grantedBy,
|
|
13137
|
+
reason: a.reason ?? "",
|
|
13138
|
+
...v.all ? { revoked: day2(a.revokedAt) } : {}
|
|
13139
|
+
}));
|
|
13140
|
+
return out(r, () => rows.length ? table(rows, ["staff", "client", "since", "by", "reason", ...v.all ? ["revoked"] : []]) : dim(t("No assignments.", "Sin asignaciones.")));
|
|
13141
|
+
}
|
|
13142
|
+
if (sub === "assign" || sub === "unassign") {
|
|
13143
|
+
if (!staff || !client) throw usage(t("Missing emails.", "Faltan correos."), `ghosty staff ${sub} <staff-email> <client-email>${sub === "assign" ? " [--reason TEXT]" : ""}`);
|
|
13144
|
+
if (sub === "assign") {
|
|
13145
|
+
const r2 = await api("/api/v2/staff/assignments", { method: "POST", body: { staff, client, ...v.reason ? { reason: v.reason } : {} } });
|
|
13146
|
+
return out(
|
|
13147
|
+
r2,
|
|
13148
|
+
() => r2.already ? dim(t(`${r2.staff} already serves ${r2.client}.`, `${r2.staff} ya atend\xEDa a ${r2.client}.`)) : `${lavender("\u2713")} ${t(`${r2.staff} now serves ${r2.client}: agents, documents, databases and boards, with no keys, billing or transfers (logged).`, `${r2.staff} ahora atiende a ${r2.client}: agentes, documentos, bases y tableros, sin llaves, cobro ni traspasos (queda en bit\xE1cora).`)}`
|
|
13149
|
+
);
|
|
13150
|
+
}
|
|
13151
|
+
const retry = `ghosty staff unassign ${staff} ${client} --yes`;
|
|
13152
|
+
requireYesIfHeadless(v.yes, retry);
|
|
13153
|
+
if (!v.yes) await confirm(t(`Stop ${staff} serving ${client}? It cuts on their next click.`, `\xBFQue ${staff} deje de atender a ${client}? Se corta en su siguiente clic.`), { retry });
|
|
13154
|
+
const r = await api("/api/v2/staff/assignments", { method: "DELETE", body: { staff, client } });
|
|
13155
|
+
return out(r, () => r.revoked ? `${lavender("\u2713")} ${t(`${r.staff} no longer serves ${r.client}.`, `${r.staff} ya no atiende a ${r.client}.`)}` : dim(t("There was no active assignment.", "No hab\xEDa asignaci\xF3n activa.")));
|
|
13156
|
+
}
|
|
13157
|
+
throw usage(t(`Unknown staff subcommand: ${sub}.`, `Subcomando de staff desconocido: ${sub}.`), "ghosty staff ls|assign|unassign <staff-email> [client-email]");
|
|
13158
|
+
}
|
|
13159
|
+
|
|
13047
13160
|
// src/commands/support.ts
|
|
13048
13161
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
13049
13162
|
var enc12 = encodeURIComponent;
|
|
@@ -13286,6 +13399,8 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
13286
13399
|
spaces rename <old> <new> Change its slug only [--dry-run]
|
|
13287
13400
|
spaces transfer <workspace> --to EMAIL New owner; agents go with it and their boxes are recycled [--keep-as admin|member|none] [--copy-keys] [--dry-run]
|
|
13288
13401
|
spaces log <workspace> Its log: transfers, staff in/out, renewals (owner or staff) [--since 30d] [--action workspace]
|
|
13402
|
+
staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
|
|
13403
|
+
staff assign|unassign <staff> <client> Staff sees and runs that account's agents, documents, databases and boards as themselves (no keys, billing or transfers; logged) [--reason]
|
|
13289
13404
|
|
|
13290
13405
|
${bold("Agents")}
|
|
13291
13406
|
agents ls List your agents [--engine E] [--ids: only ids, for xargs] \xB7 --user EMAIL --app all|android|ios|desktop: as their app sees it (staff)
|
|
@@ -13300,7 +13415,8 @@ ${bold("Agents")}
|
|
|
13300
13415
|
[--connect google-drive,\u2026] [--disconnect \u2026] give/remove access to your connectors
|
|
13301
13416
|
[--channels wa=on,teams=off] turn channels on/off (wa = personal WhatsApp)
|
|
13302
13417
|
[--voice elevenlabs:ID | kokoro:em_santa] [--voice-replies auto|off] [--auto-stage on|off]
|
|
13303
|
-
[--quote iva=
|
|
13418
|
+
[--quote iva=16,iva-incluido=true,iva.GRANEL=16,solo-factura=true,prefix=SFI] house cotizar tool config (issuer, VAT rules, folio)
|
|
13419
|
+
[--catalog productos.csv|json] its catalog: sku,nombre,precio[,unidad,categoria]
|
|
13304
13420
|
[--toolsets crm,sales | +crm,-sales] gs tool groups it gets
|
|
13305
13421
|
[--prompt-base AGENT|none --prompt-overlay FILE [--dry-run]] prompt = another agent's + edits, kept in sync
|
|
13306
13422
|
[--tool wa:tool=off,\u2026] [--bag NAME|none] [--avatar URL|FILE] a tool per channel \xB7 its token bag (staff) \xB7 its face in Teams
|
|
@@ -13429,6 +13545,8 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
13429
13545
|
spaces rename <viejo> <nuevo> Cambia s\xF3lo su slug [--dry-run]
|
|
13430
13546
|
spaces transfer <espacio> --to CORREO Due\xF1o nuevo; los agentes se van con \xE9l y se reciclan sus cajas [--keep-as admin|member|none] [--copy-keys] [--dry-run]
|
|
13431
13547
|
spaces log <espacio> Su bit\xE1cora: traspasos, staff que entra o sale, renovaciones (due\xF1o o staff) [--since 30d] [--action workspace]
|
|
13548
|
+
staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
|
|
13549
|
+
staff assign|unassign <staff> <cliente> El staff ve y opera agentes, documentos, bases y tableros de esa cuenta como s\xED mismo (sin llaves, cobro ni traspasos; queda en bit\xE1cora) [--reason]
|
|
13432
13550
|
|
|
13433
13551
|
${bold("Agentes")}
|
|
13434
13552
|
agents ls Lista tus agentes [--engine E] [--ids: s\xF3lo ids, para xargs] \xB7 --user CORREO --app all|android|ios|desktop: como lo ve su app (staff)
|
|
@@ -13443,7 +13561,8 @@ ${bold("Agentes")}
|
|
|
13443
13561
|
[--connect google-drive,\u2026] [--disconnect \u2026] dale o qu\xEDtale acceso a tus conectores
|
|
13444
13562
|
[--channels wa=on,teams=off] prende/apaga canales (wa = WhatsApp personal)
|
|
13445
13563
|
[--voice elevenlabs:ID | kokoro:em_santa] [--voice-replies auto|off] [--auto-stage on|off]
|
|
13446
|
-
[--quote iva=
|
|
13564
|
+
[--quote iva=16,iva-incluido=true,iva.GRANEL=16,solo-factura=true,prefix=SFI] config de la tool de casa cotizar (emisor, reglas de IVA, folio)
|
|
13565
|
+
[--catalog productos.csv|json] su cat\xE1logo: sku,nombre,precio[,unidad,categoria]
|
|
13447
13566
|
[--toolsets crm,sales | +crm,-sales] grupos de tools de gs que recibe
|
|
13448
13567
|
[--prompt-base AGENTE|none --prompt-overlay ARCHIVO [--dry-run]] prompt = el de otro agente + ediciones, sincronizado
|
|
13449
13568
|
[--tool wa:tool=off,\u2026] [--bag NOMBRE|none] [--avatar URL|ARCHIVO] una tool por canal \xB7 su bolsa de tokens (staff) \xB7 su cara en Teams
|
|
@@ -13548,7 +13667,7 @@ ${bold("Opciones globales")}
|
|
|
13548
13667
|
${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorrecto \xB7 3 sin sesi\xF3n
|
|
13549
13668
|
${dim("Nota: `ghosty` puede chocar con otro binario en tu PATH (p. ej. la TUI de Ghosty). Rev\xEDsalo con `which -a ghosty`; corre `npx @ghostystudio/cli` para ir a la segura.")}
|
|
13550
13669
|
${dim("Documentaci\xF3n: https://www.ghosty.studio/docs/cli")}`;
|
|
13551
|
-
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "partner", "me", "channels", "board", "boards", "credentials", "connectors", "browser", "docs", "help"];
|
|
13670
|
+
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "partner", "me", "channels", "board", "boards", "credentials", "connectors", "browser", "docs", "help"];
|
|
13552
13671
|
var AGENTS_SUBS = ["ls", "create", "get", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "box"];
|
|
13553
13672
|
function unknown(what, input, known, helpCmd) {
|
|
13554
13673
|
const s = suggest(input, known);
|
|
@@ -13690,6 +13809,7 @@ async function main() {
|
|
|
13690
13809
|
days: { type: "string" },
|
|
13691
13810
|
voice: { type: "string" },
|
|
13692
13811
|
quote: { type: "string" },
|
|
13812
|
+
catalog: { type: "string" },
|
|
13693
13813
|
"voice-replies": { type: "string" },
|
|
13694
13814
|
"auto-stage": { type: "string" },
|
|
13695
13815
|
"from-env": { type: "string" },
|
|
@@ -13724,6 +13844,7 @@ async function main() {
|
|
|
13724
13844
|
recurring: { type: "string" },
|
|
13725
13845
|
"hard-cap": { type: "string" },
|
|
13726
13846
|
note: { type: "string" },
|
|
13847
|
+
reason: { type: "string" },
|
|
13727
13848
|
bag: { type: "string" },
|
|
13728
13849
|
avatar: { type: "string" },
|
|
13729
13850
|
tool: { type: "string" },
|
|
@@ -13777,7 +13898,7 @@ async function main() {
|
|
|
13777
13898
|
const tokens = splitTokens(pos, v);
|
|
13778
13899
|
globals.token = tokens.session;
|
|
13779
13900
|
globals.profile = v.profile;
|
|
13780
|
-
if (v.version) return out({ version: "0.
|
|
13901
|
+
if (v.version) return out({ version: "0.47.0" }, () => "0.47.0");
|
|
13781
13902
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
13782
13903
|
const context = (await readConfig()).workspace;
|
|
13783
13904
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -13918,6 +14039,8 @@ async function main() {
|
|
|
13918
14039
|
case "space":
|
|
13919
14040
|
case "workspaces":
|
|
13920
14041
|
return spacesCmd(sub, a1, a2, v, context);
|
|
14042
|
+
case "staff":
|
|
14043
|
+
return staffCmd(sub, a1, a2, v);
|
|
13921
14044
|
case "plan":
|
|
13922
14045
|
return planCmd(sub, a1, v, context);
|
|
13923
14046
|
case "me":
|
|
@@ -13935,7 +14058,7 @@ async function main() {
|
|
|
13935
14058
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
13936
14059
|
}
|
|
13937
14060
|
}
|
|
13938
|
-
var notice = updateNotice("0.
|
|
14061
|
+
var notice = updateNotice("0.47.0").catch(() => null);
|
|
13939
14062
|
main().then(
|
|
13940
14063
|
async () => {
|
|
13941
14064
|
const n = await notice;
|
package/package.json
CHANGED