@ghostystudio/cli 0.45.0 → 0.46.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 +4 -0
- package/dist/index.js +84 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -103,6 +103,10 @@ 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.46.0
|
|
107
|
+
|
|
108
|
+
- 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».
|
|
109
|
+
|
|
106
110
|
### Changes in 0.45.0
|
|
107
111
|
|
|
108
112
|
- 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.46.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.46.0"}`,
|
|
8468
8468
|
"accept-language": lang(),
|
|
8469
8469
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
8470
8470
|
...opts.headers
|
|
@@ -9738,7 +9738,7 @@ async function call(path, v, init = {}) {
|
|
|
9738
9738
|
"x-ghosty-ts": ts,
|
|
9739
9739
|
"x-ghosty-sig": sig,
|
|
9740
9740
|
"content-type": "application/json",
|
|
9741
|
-
"user-agent": `ghosty-cli/${"0.
|
|
9741
|
+
"user-agent": `ghosty-cli/${"0.46.0"}`
|
|
9742
9742
|
},
|
|
9743
9743
|
body: method === "GET" ? void 0 : raw
|
|
9744
9744
|
});
|
|
@@ -11598,6 +11598,18 @@ var HELPS_ES = {
|
|
|
11598
11598
|
["--yes", "s\xE1ltate la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
11599
11599
|
],
|
|
11600
11600
|
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."]
|
|
11601
|
+
},
|
|
11602
|
+
staff: {
|
|
11603
|
+
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.",
|
|
11604
|
+
flags: [
|
|
11605
|
+
["--all", "ls: tambi\xE9n las asignaciones revocadas"],
|
|
11606
|
+
["--reason TEXT", "assign: por qu\xE9 (va a la bit\xE1cora)"],
|
|
11607
|
+
["--yes", "unassign: s\xE1ltate la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
11608
|
+
],
|
|
11609
|
+
notes: [
|
|
11610
|
+
"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.",
|
|
11611
|
+
"Revocar corta en el siguiente request. Asignar dos veces no hace nada (una sola activa por par)."
|
|
11612
|
+
]
|
|
11601
11613
|
}
|
|
11602
11614
|
};
|
|
11603
11615
|
var HELP_ALIASES = { creds: "credentials", conectores: "connectors", board: "cards", conversations: "chat", workspaces: "spaces" };
|
|
@@ -12229,6 +12241,25 @@ HELPS.sites = {
|
|
|
12229
12241
|
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
12242
|
learn: `${REF}#sitios`
|
|
12231
12243
|
};
|
|
12244
|
+
HELPS.staff = {
|
|
12245
|
+
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.",
|
|
12246
|
+
usage: [
|
|
12247
|
+
"ghosty staff ls [staff-email] [client-email] [--all]",
|
|
12248
|
+
"ghosty staff assign <staff-email> <client-email> [--reason TEXT]",
|
|
12249
|
+
"ghosty staff unassign <staff-email> <client-email> [--yes]"
|
|
12250
|
+
],
|
|
12251
|
+
flags: [
|
|
12252
|
+
["--all", "ls: also revoked assignments"],
|
|
12253
|
+
["--reason TEXT", "assign: why (goes to the audit log)"],
|
|
12254
|
+
["--yes", "unassign: skip the confirmation (required without a terminal)"]
|
|
12255
|
+
],
|
|
12256
|
+
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"],
|
|
12257
|
+
notes: [
|
|
12258
|
+
"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.",
|
|
12259
|
+
"Revoking cuts on the next request. Assigning twice is a no-op (one active assignment per pair)."
|
|
12260
|
+
],
|
|
12261
|
+
learn: `${REF}#staff-asignado`
|
|
12262
|
+
};
|
|
12232
12263
|
function helpText(cmd) {
|
|
12233
12264
|
const base = HELPS[cmd];
|
|
12234
12265
|
if (!base) return void 0;
|
|
@@ -12843,7 +12874,7 @@ ${dim(t(`${total2} message(s) unanswered for lack of balance in ${r.days} day(s)
|
|
|
12843
12874
|
d.noQuota += x.noQuota;
|
|
12844
12875
|
days.set(x.day, d);
|
|
12845
12876
|
}
|
|
12846
|
-
rows = [...days].map(([
|
|
12877
|
+
rows = [...days].map(([day3, x]) => ({ day: day3, ...fmt2(x) }));
|
|
12847
12878
|
} else rows = r.agents.map((x) => ({ agent: x.agent, ...fmt2(x) }));
|
|
12848
12879
|
const cols = [...by.has("day") ? ["day"] : [], ...by.has("agent") ? ["agent"] : [], "turns", "failed", "tokens", "no balance"];
|
|
12849
12880
|
const total = r.agents.reduce((n, a) => n + a.billable, 0);
|
|
@@ -13044,6 +13075,43 @@ ${dim(t("Links with the old slug may stop working.", "Las ligas con el slug viej
|
|
|
13044
13075
|
}
|
|
13045
13076
|
}
|
|
13046
13077
|
|
|
13078
|
+
// src/commands/staff.ts
|
|
13079
|
+
var day2 = (iso) => iso ? iso.slice(0, 10) : "";
|
|
13080
|
+
async function staffCmd(sub, staff, client, v) {
|
|
13081
|
+
if (!sub || sub === "ls" || sub === "list") {
|
|
13082
|
+
const q = new URLSearchParams();
|
|
13083
|
+
if (staff) q.set("staff", staff);
|
|
13084
|
+
if (client) q.set("client", client);
|
|
13085
|
+
if (v.all) q.set("all", "1");
|
|
13086
|
+
const r = await api(`/api/v2/staff/assignments${q.toString() ? `?${q}` : ""}`);
|
|
13087
|
+
const rows = r.assignments.map((a) => ({
|
|
13088
|
+
staff: a.staff.email,
|
|
13089
|
+
client: a.client.email,
|
|
13090
|
+
since: day2(a.createdAt),
|
|
13091
|
+
by: a.grantedBy,
|
|
13092
|
+
reason: a.reason ?? "",
|
|
13093
|
+
...v.all ? { revoked: day2(a.revokedAt) } : {}
|
|
13094
|
+
}));
|
|
13095
|
+
return out(r, () => rows.length ? table(rows, ["staff", "client", "since", "by", "reason", ...v.all ? ["revoked"] : []]) : dim(t("No assignments.", "Sin asignaciones.")));
|
|
13096
|
+
}
|
|
13097
|
+
if (sub === "assign" || sub === "unassign") {
|
|
13098
|
+
if (!staff || !client) throw usage(t("Missing emails.", "Faltan correos."), `ghosty staff ${sub} <staff-email> <client-email>${sub === "assign" ? " [--reason TEXT]" : ""}`);
|
|
13099
|
+
if (sub === "assign") {
|
|
13100
|
+
const r2 = await api("/api/v2/staff/assignments", { method: "POST", body: { staff, client, ...v.reason ? { reason: v.reason } : {} } });
|
|
13101
|
+
return out(
|
|
13102
|
+
r2,
|
|
13103
|
+
() => 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).`)}`
|
|
13104
|
+
);
|
|
13105
|
+
}
|
|
13106
|
+
const retry = `ghosty staff unassign ${staff} ${client} --yes`;
|
|
13107
|
+
requireYesIfHeadless(v.yes, retry);
|
|
13108
|
+
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 });
|
|
13109
|
+
const r = await api("/api/v2/staff/assignments", { method: "DELETE", body: { staff, client } });
|
|
13110
|
+
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.")));
|
|
13111
|
+
}
|
|
13112
|
+
throw usage(t(`Unknown staff subcommand: ${sub}.`, `Subcomando de staff desconocido: ${sub}.`), "ghosty staff ls|assign|unassign <staff-email> [client-email]");
|
|
13113
|
+
}
|
|
13114
|
+
|
|
13047
13115
|
// src/commands/support.ts
|
|
13048
13116
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
13049
13117
|
var enc12 = encodeURIComponent;
|
|
@@ -13286,6 +13354,8 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
13286
13354
|
spaces rename <old> <new> Change its slug only [--dry-run]
|
|
13287
13355
|
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
13356
|
spaces log <workspace> Its log: transfers, staff in/out, renewals (owner or staff) [--since 30d] [--action workspace]
|
|
13357
|
+
staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
|
|
13358
|
+
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
13359
|
|
|
13290
13360
|
${bold("Agents")}
|
|
13291
13361
|
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)
|
|
@@ -13429,6 +13499,8 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
13429
13499
|
spaces rename <viejo> <nuevo> Cambia s\xF3lo su slug [--dry-run]
|
|
13430
13500
|
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
13501
|
spaces log <espacio> Su bit\xE1cora: traspasos, staff que entra o sale, renovaciones (due\xF1o o staff) [--since 30d] [--action workspace]
|
|
13502
|
+
staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
|
|
13503
|
+
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
13504
|
|
|
13433
13505
|
${bold("Agentes")}
|
|
13434
13506
|
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)
|
|
@@ -13548,7 +13620,7 @@ ${bold("Opciones globales")}
|
|
|
13548
13620
|
${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorrecto \xB7 3 sin sesi\xF3n
|
|
13549
13621
|
${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
13622
|
${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"];
|
|
13623
|
+
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
13624
|
var AGENTS_SUBS = ["ls", "create", "get", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "box"];
|
|
13553
13625
|
function unknown(what, input, known, helpCmd) {
|
|
13554
13626
|
const s = suggest(input, known);
|
|
@@ -13724,6 +13796,7 @@ async function main() {
|
|
|
13724
13796
|
recurring: { type: "string" },
|
|
13725
13797
|
"hard-cap": { type: "string" },
|
|
13726
13798
|
note: { type: "string" },
|
|
13799
|
+
reason: { type: "string" },
|
|
13727
13800
|
bag: { type: "string" },
|
|
13728
13801
|
avatar: { type: "string" },
|
|
13729
13802
|
tool: { type: "string" },
|
|
@@ -13777,7 +13850,7 @@ async function main() {
|
|
|
13777
13850
|
const tokens = splitTokens(pos, v);
|
|
13778
13851
|
globals.token = tokens.session;
|
|
13779
13852
|
globals.profile = v.profile;
|
|
13780
|
-
if (v.version) return out({ version: "0.
|
|
13853
|
+
if (v.version) return out({ version: "0.46.0" }, () => "0.46.0");
|
|
13781
13854
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
13782
13855
|
const context = (await readConfig()).workspace;
|
|
13783
13856
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -13918,6 +13991,8 @@ async function main() {
|
|
|
13918
13991
|
case "space":
|
|
13919
13992
|
case "workspaces":
|
|
13920
13993
|
return spacesCmd(sub, a1, a2, v, context);
|
|
13994
|
+
case "staff":
|
|
13995
|
+
return staffCmd(sub, a1, a2, v);
|
|
13921
13996
|
case "plan":
|
|
13922
13997
|
return planCmd(sub, a1, v, context);
|
|
13923
13998
|
case "me":
|
|
@@ -13935,7 +14010,7 @@ async function main() {
|
|
|
13935
14010
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
13936
14011
|
}
|
|
13937
14012
|
}
|
|
13938
|
-
var notice = updateNotice("0.
|
|
14013
|
+
var notice = updateNotice("0.46.0").catch(() => null);
|
|
13939
14014
|
main().then(
|
|
13940
14015
|
async () => {
|
|
13941
14016
|
const n = await notice;
|
package/package.json
CHANGED