@ghostystudio/cli 0.78.0 → 0.83.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 +5 -0
- package/dist/index.js +237 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@ ghosty engines ls [--models] # valid --engine / --model
|
|
|
23
23
|
ghosty bags ls|create|set|rm <workspace> ["bag"] [--tokens 20M] [--recurring on|off] [--hard-cap on|off] [--note] # token bags (changing: staff)
|
|
24
24
|
ghosty spaces create <slug> [--combo …: staff] [--dry-run] # yours, trial
|
|
25
25
|
ghosty spaces renew <workspace> --until YYYY-MM-DD [--note] [--dry-run] # staff
|
|
26
|
+
ghosty spaces plan <workspace> trial|pro|empresarial [--courtesy] [--until YYYY-MM-DD] [--note] [--dry-run] # staff, same rules as /admin/tenants, no Stripe charge
|
|
26
27
|
ghosty spaces rename <old> <new> [--dry-run] # staff, slug only
|
|
27
28
|
ghosty spaces transfer <workspace> --to EMAIL [--keep-as admin] [--copy-keys] [--dry-run] # staff, new owner
|
|
28
29
|
ghosty agents ls [--engine E] [--ids] [--sponsor EMAIL | --owner EMAIL] # --sponsor/--owner: any account (Ghosty staff)
|
|
@@ -145,6 +146,10 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
|
|
|
145
146
|
|
|
146
147
|
Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
147
148
|
|
|
149
|
+
### Changes in 0.83.0
|
|
150
|
+
|
|
151
|
+
- `spaces plan <workspace> trial|pro|empresarial [--courtesy] [--until YYYY-MM-DD] [--note] [--dry-run]` (staff): change a workspace's plan without opening /admin/tenants, with the same rules. The dry run shows plan, model cap, tokens (used/included, hard cap or not) and «paid until» before → after. Never charges Stripe nor emails the customer; `--courtesy` records it as a no-charge courtesy in the plan note and the audit (`workspace.plan`).
|
|
152
|
+
|
|
148
153
|
### Changes in 0.75.0
|
|
149
154
|
|
|
150
155
|
- `ads watch [ls]` and `ads watch run [--dry-run]` (staff): the campaign watch. Every hour gs checks the connected Meta ad accounts and the ads-only WhatsApp numbers and alerts staff once when an active campaign is paused or stops delivering, the account has a payment pending, the Meta token expires within 7 days, or a number goes 24 h without ad leads.
|
package/dist/index.js
CHANGED
|
@@ -1175,7 +1175,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
|
|
|
1175
1175
|
const req = httpsRequest(`${base}${path}`, {
|
|
1176
1176
|
method: "POST",
|
|
1177
1177
|
timeout: timeoutMs,
|
|
1178
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
1178
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.83.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
1179
1179
|
}, (res) => {
|
|
1180
1180
|
let buf = "";
|
|
1181
1181
|
res.on("data", (c) => buf += c);
|
|
@@ -1217,7 +1217,7 @@ async function request(path, opts = {}, retried = false) {
|
|
|
1217
1217
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
1218
1218
|
headers: {
|
|
1219
1219
|
authorization: `Bearer ${token}`,
|
|
1220
|
-
"user-agent": `ghosty-cli/${"0.
|
|
1220
|
+
"user-agent": `ghosty-cli/${"0.83.0"}`,
|
|
1221
1221
|
"accept-language": lang(),
|
|
1222
1222
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
1223
1223
|
...opts.headers
|
|
@@ -9017,7 +9017,7 @@ ${bagsText(r)}`);
|
|
|
9017
9017
|
}
|
|
9018
9018
|
}
|
|
9019
9019
|
async function spacesCmd(sub, slug, arg, v, context) {
|
|
9020
|
-
const ex = "ghosty spaces ls [--user EMAIL] \xB7 create <slug> [--combo teams|sales|both|none] [--dry-run] \xB7 join|leave <workspace> \xB7 set <workspace> --combo teams|sales|both|none | --model-cap 0.25|1|4|none | --house-claude on|off \xB7 renew <workspace> --until 2026-11-01 [--note TEXT] \xB7 rename <old> <new> [--dry-run] \xB7 archive|restore <workspace> [--dry-run] \xB7 transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] \xB7 log <workspace> [--since 30d] [--action workspace]";
|
|
9020
|
+
const ex = "ghosty spaces ls [--user EMAIL] \xB7 create <slug> [--combo teams|sales|both|none] [--dry-run] \xB7 join|leave <workspace> \xB7 set <workspace> --combo teams|sales|both|none | --model-cap 0.25|1|4|none | --house-claude on|off \xB7 renew <workspace> --until 2026-11-01 [--note TEXT] \xB7 plan <workspace> trial|pro|empresarial [--courtesy] [--until DATE] [--note TEXT] \xB7 rename <old> <new> [--dry-run] \xB7 archive|restore <workspace> [--dry-run] \xB7 transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] \xB7 log <workspace> [--since 30d] [--action workspace]";
|
|
9021
9021
|
if (!sub || sub === "ls" || sub === "list") {
|
|
9022
9022
|
const r = await api(`/api/v2/workspaces${v.user ? `?user=${enc2(v.user)}` : ""}`);
|
|
9023
9023
|
const rows = r.workspaces.map((w) => ({ workspace: w.slug, role: w.role ?? "", plan: w.plan, combo: w.combo, owner: w.owner ?? "", paid: w.paidUntil ?? "" }));
|
|
@@ -9085,6 +9085,24 @@ ${t("Renew?", "\xBFRenovar?")}`, { yes: v.yes, retry: `ghosty spaces renew ${slu
|
|
|
9085
9085
|
const r = await api(path, { method: "POST", body: { until: v.until, ...v.note ? { note: v.note } : {} } });
|
|
9086
9086
|
return out(r, () => `${lavender("\u2713")} ${line2} ${dim(t("(logged in the workspace's audit)", "(queda en la bit\xE1cora del espacio)"))}`);
|
|
9087
9087
|
}
|
|
9088
|
+
if (sub === "plan") {
|
|
9089
|
+
slug = needSpace(slug ?? context, "ghosty spaces plan <workspace> pro --courtesy --dry-run");
|
|
9090
|
+
if (!arg) throw usage(t("Which plan?", "\xBFQu\xE9 plan?"), `ghosty spaces plan ${slug} trial|pro|empresarial [--courtesy] [--until YYYY-MM-DD] --dry-run`);
|
|
9091
|
+
const path = wsPath(slug, "/plan");
|
|
9092
|
+
const body = { plan: arg, ...v.courtesy ? { courtesy: true } : {}, ...v.until ? { until: v.until } : {}, ...v.note ? { note: v.note } : {} };
|
|
9093
|
+
const plan = await api(path, { method: "POST", body: { ...body, dryRun: true } });
|
|
9094
|
+
const text = planChangeText(plan);
|
|
9095
|
+
if (!plan.changed && !v.courtesy && !v.note) return out(plan, () => dim(t(`Nothing to do: ${plan.workspace} is already ${plan.before.plan}.`, `Nada que hacer: ${plan.workspace} ya es ${plan.before.plan}.`)));
|
|
9096
|
+
if (v["dry-run"]) return out(plan, () => `${text}
|
|
9097
|
+
${dim(t("Dry run: nothing changed.", "Simulaci\xF3n: no cambi\xF3 nada."))}`);
|
|
9098
|
+
const retry = `ghosty spaces plan ${slug} ${arg}${v.courtesy ? " --courtesy" : ""}${v.until ? ` --until ${v.until}` : ""}${v.note ? ` --note ${JSON.stringify(v.note)}` : ""}`;
|
|
9099
|
+
requireYesIfHeadless(v.yes, retry);
|
|
9100
|
+
await confirm(`${text}
|
|
9101
|
+
${t("Change the plan?", "\xBFCambiar el plan?")}`, { yes: v.yes, retry });
|
|
9102
|
+
const r = await api(path, { method: "POST", body });
|
|
9103
|
+
return out(r, () => `${lavender("\u2713")} ${planChangeText(r)}
|
|
9104
|
+
${dim(t("(logged in the workspace's audit)", "(queda en la bit\xE1cora del espacio)"))}`);
|
|
9105
|
+
}
|
|
9088
9106
|
if (sub === "rename") {
|
|
9089
9107
|
slug = needSpace(slug, ex);
|
|
9090
9108
|
if (!arg) throw usage(t("Missing the new name.", "Falta el nombre nuevo."), `ghosty spaces rename ${slug} <new> --dry-run`);
|
|
@@ -9141,6 +9159,20 @@ ${r.warnings.map((w) => red(` \xB7 ${serverText(w)}`)).join("\n")}` : ""}`);
|
|
|
9141
9159
|
}
|
|
9142
9160
|
throw usage(t(`Unknown spaces subcommand: ${sub ?? "(none)"}.`, `Subcomando de spaces desconocido: ${sub ?? "(ninguno)"}.`), ex);
|
|
9143
9161
|
}
|
|
9162
|
+
function planChangeText(p) {
|
|
9163
|
+
const cap = (x) => x === null ? t("no cap", "sin tope") : `${x}\xD7`;
|
|
9164
|
+
const tok = (s2) => `${fmtTokens(s2.tokensUsed)}/${fmtTokens(s2.tokensIncluded)}${s2.hardCap ? t(" (hard cap)", " (corta)") : ""}`;
|
|
9165
|
+
const paid = (s2) => `${s2.paidUntil ?? "\u2014"}${s2.expires ? t(" (trial ends)", " (fin de prueba)") : ""}`;
|
|
9166
|
+
const row = (label, a, b) => ` ${label.padEnd(10)} ${a} \u2192 ${a === b ? b : bold(b)}`;
|
|
9167
|
+
return [
|
|
9168
|
+
`${bold(p.workspace)}${p.courtesy ? dim(t(" \xB7 courtesy, no charge", " \xB7 cortes\xEDa, sin cobro")) : ""}`,
|
|
9169
|
+
row("plan", p.before.plan, p.after.plan),
|
|
9170
|
+
row(t("model cap", "modelos"), cap(p.before.modelCap), cap(p.after.modelCap)),
|
|
9171
|
+
row("tokens", tok(p.before), tok(p.after)),
|
|
9172
|
+
row(t("paid until", "pagado"), paid(p.before), paid(p.after)),
|
|
9173
|
+
...p.warnings.map((w) => red(` \xB7 ${serverText(w)}`))
|
|
9174
|
+
].join("\n");
|
|
9175
|
+
}
|
|
9144
9176
|
async function workspaceUsage(slug, v) {
|
|
9145
9177
|
slug = needSpace(slug, "ghosty usage --workspace <slug> --by agent,day --days 14");
|
|
9146
9178
|
const r = await api(wsPath(slug, `/usage?days=${enc2(v.days ?? "14")}`));
|
|
@@ -11205,7 +11237,7 @@ async function call(path, v, init = {}) {
|
|
|
11205
11237
|
"x-ghosty-ts": ts,
|
|
11206
11238
|
"x-ghosty-sig": sig,
|
|
11207
11239
|
"content-type": "application/json",
|
|
11208
|
-
"user-agent": `ghosty-cli/${"0.
|
|
11240
|
+
"user-agent": `ghosty-cli/${"0.83.0"}`
|
|
11209
11241
|
},
|
|
11210
11242
|
body: method === "GET" ? void 0 : raw
|
|
11211
11243
|
});
|
|
@@ -11484,32 +11516,57 @@ async function partnerCmd(sub, a1, a2, v, a3) {
|
|
|
11484
11516
|
|
|
11485
11517
|
// src/commands/image.ts
|
|
11486
11518
|
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
11519
|
+
import { extname as extname2 } from "node:path";
|
|
11487
11520
|
init_util();
|
|
11488
11521
|
init_i18n();
|
|
11489
|
-
|
|
11490
|
-
if (
|
|
11491
|
-
|
|
11492
|
-
}
|
|
11522
|
+
function outPath(base, i, n) {
|
|
11523
|
+
if (n === 1) return base;
|
|
11524
|
+
const ext = extname2(base);
|
|
11525
|
+
return `${ext ? base.slice(0, -ext.length) : base}-${i + 1}${ext}`;
|
|
11526
|
+
}
|
|
11527
|
+
async function imageCmd(sub, a1, a2, v) {
|
|
11528
|
+
const edit = sub === "edit";
|
|
11529
|
+
if (!edit && sub !== "generate" && sub !== "gen") {
|
|
11530
|
+
throw usage(t(`Unknown image subcommand: ${sub ?? "(none)"}.`, `Subcomando de image desconocido: ${sub ?? "(ninguno)"}.`), t("Try", "Prueba") + ': ghosty image generate "a cat astronaut" [--ref URL] [--aspect 16:9] \xB7 ghosty image edit URL "add a big -50 % in the corner"');
|
|
11531
|
+
}
|
|
11532
|
+
const base = edit ? a1 : void 0;
|
|
11533
|
+
const prompt = edit ? a2 : a1;
|
|
11534
|
+
if (edit && !base?.trim()) throw usage(t("Missing the URL of the image to edit.", "Falta la URL de la imagen a editar."), t("Example", "Ejemplo") + ': ghosty image edit https://img.ghosty.studio/u/x/promo.png "add a big red -50 % in the top right corner" --text "-50 %"');
|
|
11493
11535
|
if (!prompt?.trim()) throw usage(t("Missing the prompt.", "Falta el prompt."), t("Example", "Ejemplo") + ': ghosty image generate "my mascot in a Halloween scene" --ref https://example.com/mascot.png --aspect 16:9');
|
|
11494
11536
|
const body = {
|
|
11495
11537
|
prompt,
|
|
11538
|
+
...base ? { baseImageUrl: base } : {},
|
|
11496
11539
|
...v.ref?.length ? { referenceUrls: v.ref } : {},
|
|
11540
|
+
...v["style-ref"]?.length ? { styleUrls: v["style-ref"] } : {},
|
|
11541
|
+
...v.scene?.length ? { sceneUrls: v.scene } : {},
|
|
11542
|
+
...v.direction?.length ? { directions: v.direction } : {},
|
|
11543
|
+
...v.variants ? { variants: Number(v.variants) } : {},
|
|
11544
|
+
...v.size ? { size: v.size } : {},
|
|
11545
|
+
...v.text ? { text: v.text } : {},
|
|
11497
11546
|
...v.aspect ? { aspectRatio: v.aspect } : {},
|
|
11498
11547
|
...v.tenant ? { tenant: { externalId: v.tenant } } : {},
|
|
11499
11548
|
...v.agent ? { agent: v.agent } : {}
|
|
11500
11549
|
};
|
|
11501
11550
|
const r = await json("/api/v2/partner/images", v, { method: "POST", body });
|
|
11551
|
+
const images = r.images?.length ? r.images : [r];
|
|
11552
|
+
const saved = [];
|
|
11502
11553
|
if (v.out) {
|
|
11503
|
-
const
|
|
11504
|
-
|
|
11505
|
-
|
|
11554
|
+
for (const [i, img] of images.entries()) {
|
|
11555
|
+
const res = await fetch(img.url);
|
|
11556
|
+
if (!res.ok) throw new Error(t(`Could not download the image (${res.status}).`, `No se pudo bajar la imagen (${res.status}).`));
|
|
11557
|
+
const file = outPath(v.out, i, images.length);
|
|
11558
|
+
await writeFile6(file, Buffer.from(await res.arrayBuffer()));
|
|
11559
|
+
saved.push(file);
|
|
11560
|
+
}
|
|
11506
11561
|
}
|
|
11562
|
+
const how = { edit: t("edited", "editada"), compose: t("composed from references", "compuesta con referencias"), generate: t("generated", "generada") }[r.mode] ?? r.mode;
|
|
11507
11563
|
return out(
|
|
11508
11564
|
r,
|
|
11509
11565
|
() => [
|
|
11510
|
-
|
|
11511
|
-
dim(`${
|
|
11512
|
-
...
|
|
11566
|
+
...images.map((img) => `${img.url}${img.direction ? dim(` \xB7 ${img.direction}`) : ""}${img.width && img.height ? dim(` \xB7 ${img.width}\xD7${img.height}`) : ""}`),
|
|
11567
|
+
dim(`${how} \xB7 ${r.size ?? "2K"} \xB7 ${images.length}/${r.requested ?? 1} \xB7 ${t("charged", "cobrado")} USD ${r.priceUsd.toFixed(2)}`),
|
|
11568
|
+
...r.failed?.length ? [dim(t(`${r.failed.length} failed (not charged)`, `${r.failed.length} fallaron (sin cobro)`))] : [],
|
|
11569
|
+
...saved.map((f) => `${lavender("\u2713")} ${t(`saved to ${f}`, `guardada en ${f}`)}`)
|
|
11513
11570
|
].join("\n")
|
|
11514
11571
|
);
|
|
11515
11572
|
}
|
|
@@ -13285,20 +13342,31 @@ var HELPS_ES = {
|
|
|
13285
13342
|
notes: ["Revoca todos los tokens de Ghosty para Chrome que tengan tus agentes de terminal (Claude Code, CLI, @ghostystudio/browser-mcp) y desconecta la extensi\xF3n. Para volver, copia un comando nuevo del panel de la extensi\xF3n."]
|
|
13286
13343
|
},
|
|
13287
13344
|
image: {
|
|
13288
|
-
summary: "
|
|
13345
|
+
summary: "Im\xE1genes con IA (Gemini \xABNano Banana Pro\xBB) para los negocios de tu espacio de partner: generar, editar una que ya existe o componer con referencias; cobradas del saldo del espacio.",
|
|
13289
13346
|
replace: [
|
|
13290
13347
|
["our mascot dressed as a pumpkin in a Halloween scene, flat illustration, no text", "nuestra mascota disfrazada de calabaza en una escena de Halloween, ilustraci\xF3n plana, sin texto"],
|
|
13291
|
-
["a
|
|
13348
|
+
["add a big red badge in the top right corner", "a\xF1ade una etiqueta roja grande en la esquina superior derecha"],
|
|
13349
|
+
["a cozy spa with candles, warm light", "un spa acogedor con velas, luz c\xE1lida"],
|
|
13350
|
+
["flat illustration with thick outlines", "ilustraci\xF3n plana con contorno grueso"],
|
|
13351
|
+
["warm studio photo", "foto c\xE1lida de estudio"],
|
|
13352
|
+
['"change"', '"cambio"']
|
|
13292
13353
|
],
|
|
13293
13354
|
flags: [
|
|
13294
|
-
["--ref URL", "una
|
|
13295
|
-
["--
|
|
13355
|
+
["--ref URL", "una referencia de personaje u objeto (https; JPEG, PNG, WebP, GIF o SVG); se repite, hasta 6. La imagen CONSERVA ese personaje u objeto (mascota, logo, producto)"],
|
|
13356
|
+
["--style-ref URL", "una referencia de estilo (hasta 3): s\xF3lo se toma su t\xE9cnica, paleta e iluminaci\xF3n, no su contenido"],
|
|
13357
|
+
["--scene URL", "un fondo o escena a usar (hasta 2)"],
|
|
13358
|
+
["--text T", 'texto exacto que va dentro de la imagen ("-50 %", "$299"), hasta 200 caracteres'],
|
|
13359
|
+
["--direction D", "una direcci\xF3n de arte; se repite (hasta 4) y sale una imagen por direcci\xF3n para escoger"],
|
|
13360
|
+
["--variants N", "cu\xE1ntas opciones (1-4); cada una se cobra como una imagen"],
|
|
13361
|
+
["--size SIZE", "1K, 2K (default) o 4K; 4K cuesta m\xE1s"],
|
|
13362
|
+
["--aspect RATIO", "1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9 o 21:9 (edit: om\xEDtelo para conservar la del original)"],
|
|
13296
13363
|
["--tenant ID", "el negocio (externalId) para el que es: va al desglose de consumo y a su tope diario opcional"],
|
|
13297
13364
|
["--agent SLUG", "a qu\xE9 agente del partner se carga en el desglose (default: el de siempre)"],
|
|
13298
|
-
["--out FILE", "adem\xE1s baja el PNG aqu\xED"]
|
|
13365
|
+
["--out FILE", "adem\xE1s baja el PNG aqu\xED (varias: FILE-1.png, FILE-2.png\u2026)"]
|
|
13299
13366
|
],
|
|
13300
13367
|
notes: [
|
|
13301
|
-
|
|
13368
|
+
"Para cambiar una imagen que ya existe usa edit (no generate): sale la misma imagen con s\xF3lo ese cambio.",
|
|
13369
|
+
`Cada imagen se cobra aparte del saldo del espacio de partner: USD 0.25 a 1K/2K y USD 0.45 a 4K; las variantes se cobran una por una y las fallidas no se cobran. Sin saldo: 402. gs no pone topes propios; un negocio puede tener el suyo: tenants set <id> --config '{"imageDailyCap":20}'.`,
|
|
13302
13370
|
"Auth: tu login (due\xF1a del espacio; --workspace si tienes varios) o la credencial del servidor del partner en el env (GHOSTY_PARTNER_KEY + GHOSTY_PARTNER_KEY_SECRET), que entonces exige --tenant."
|
|
13303
13371
|
]
|
|
13304
13372
|
},
|
|
@@ -13579,7 +13647,7 @@ var HELPS_ES = {
|
|
|
13579
13647
|
notes: ["Lo pregunta quien administra lo preguntado: el due\xF1o del agente o del espacio, un admin del espacio, o staff.", "Dar o quitar acceso: ghosty spaces members add|rm, ghosty boards access."]
|
|
13580
13648
|
},
|
|
13581
13649
|
spaces: {
|
|
13582
|
-
summary: "Espacios: crea uno a tu nombre (prueba), lista los tuyos (o, staff, los de cualquiera) y operaciones del staff de Ghosty \u2014 entrar/salir del espacio de un cliente, cambiar su combo, mover \xABpagado hasta\xBB, renombrar su slug, cambiar de due\xF1o \u2014 y, due\xF1o o staff, archivarlo o restaurarlo. Cada cambio queda en la bit\xE1cora del espacio.",
|
|
13650
|
+
summary: "Espacios: crea uno a tu nombre (prueba), lista los tuyos (o, staff, los de cualquiera) y operaciones del staff de Ghosty \u2014 entrar/salir del espacio de un cliente, cambiar su combo o su plan, mover \xABpagado hasta\xBB, renombrar su slug, cambiar de due\xF1o \u2014 y, due\xF1o o staff, archivarlo o restaurarlo. Cada cambio queda en la bit\xE1cora del espacio.",
|
|
13583
13651
|
flags: [
|
|
13584
13652
|
["--user EMAIL", "ls (staff): los espacios de esa persona"],
|
|
13585
13653
|
["--role R", "members add: member (default: tableros + editor de los agentes del espacio, sin llaves, cobro ni traspasos) | admin (adem\xE1s invita y quita gente) | collaborator (invitado a UN room: sin asiento ni agente personal)"],
|
|
@@ -13589,8 +13657,9 @@ var HELPS_ES = {
|
|
|
13589
13657
|
["--combo C", "set (staff): teams | sales | both | none (ni Teams ni Ventas) \u2014 sin Ventas sus tableros existen pero nadie los ve; create: distinto de teams, s\xF3lo staff"],
|
|
13590
13658
|
["--model-cap X", "set (staff): el modelo m\xE1s caro que puede elegir el espacio \u2014 0.25 econ\xF3micos, 1 est\xE1ndar (Sonnet), 4 todos; none = el de su plan"],
|
|
13591
13659
|
["--house-claude on|off", "set (staff): sus agentes corren con la Claude de Ghosty si el due\xF1o no trae llave; recicla sus cajas de Claude"],
|
|
13592
|
-
["--until DATE", "renew: el nuevo \xABpagado hasta\xBB (AAAA-MM-DD)"],
|
|
13593
|
-
["--note TEXT", "renew: por qu\xE9 (va a la bit\xE1cora)"],
|
|
13660
|
+
["--until DATE", "renew, plan: el nuevo \xABpagado hasta\xBB (AAAA-MM-DD); plan sin \xE9l conserva el actual"],
|
|
13661
|
+
["--note TEXT", "renew, plan: por qu\xE9 (va a la bit\xE1cora)"],
|
|
13662
|
+
["--courtesy", "plan (staff): lo marca como cortes\xEDa sin cobro (queda en la nota del plan del espacio y en la bit\xE1cora)"],
|
|
13594
13663
|
["--to EMAIL", "transfer: el due\xF1o nuevo (si no tiene cuenta se precrea y la reclama al entrar)"],
|
|
13595
13664
|
["--keep-as R", "transfer: el rol del due\xF1o anterior \u2014 admin | member (default) | none (sale del espacio)"],
|
|
13596
13665
|
["--copy-keys", "transfer: copia las llaves de proveedor del anterior y los conectores que usan sus agentes (MercadoPago, Skydropx\u2026) que le falten al nuevo. S\xF3lo cambia el due\xF1o: documentos, bases, tableros y n\xFAmeros que usan sus agentes se van con \xE9l; lo que tambi\xE9n se usa fuera del espacio se queda y se avisa"],
|
|
@@ -13598,7 +13667,7 @@ var HELPS_ES = {
|
|
|
13598
13667
|
["-n, --dry-run", "ense\xF1a qu\xE9 cambia, no cambia nada"],
|
|
13599
13668
|
["--yes", "s\xE1ltate la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
13600
13669
|
],
|
|
13601
|
-
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.", "archive hace lo mismo que Ajustes \u2192 Archivar: el espacio sale de /app y de spaces ls, sus agentes y datos se quedan; pide escribir el slug. Deshacer: ghosty spaces restore <slug>. Queda en bit\xE1cora como workspace.archive / workspace.restore.", "transfer se lleva los agentes con el espacio: las cajas ACP se mudan al due\xF1o nuevo con su /data, las del pool se reciclan (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."]
|
|
13670
|
+
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.", "plan aplica las mismas reglas que \xABPlan y pago\xBB de /admin/tenants: de trial a pro se quitan el corte por saldo y el fin de prueba, el tope de modelos sube de 0.25\xD7 a 1\xD7 y los tokens se miden por mes natural. Nunca cobra en Stripe ni le escribe al cliente; la simulaci\xF3n ense\xF1a plan, modelos, tokens y \xABpagado hasta\xBB antes \u2192 despu\xE9s. Queda en bit\xE1cora como workspace.plan.", "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.", "archive hace lo mismo que Ajustes \u2192 Archivar: el espacio sale de /app y de spaces ls, sus agentes y datos se quedan; pide escribir el slug. Deshacer: ghosty spaces restore <slug>. Queda en bit\xE1cora como workspace.archive / workspace.restore.", "transfer se lleva los agentes con el espacio: las cajas ACP se mudan al due\xF1o nuevo con su /data, las del pool se reciclan (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."]
|
|
13602
13671
|
},
|
|
13603
13672
|
staff: {
|
|
13604
13673
|
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.",
|
|
@@ -14088,21 +14157,32 @@ var HELPS = {
|
|
|
14088
14157
|
learn: `${REF}#navegador`
|
|
14089
14158
|
},
|
|
14090
14159
|
image: {
|
|
14091
|
-
summary: "
|
|
14092
|
-
usage: [
|
|
14160
|
+
summary: "AI images (Gemini \xABNano Banana Pro\xBB) for your partner businesses: generate, edit an existing one, or compose from references; charged to the space's balance.",
|
|
14161
|
+
usage: [
|
|
14162
|
+
'ghosty image generate "prompt" [--ref URL]... [--style-ref URL]... [--scene URL] [--text T] [--direction D]... [--variants N] [--size 2K] [--aspect 16:9] [--tenant ID] [--agent SLUG] [--out FILE]',
|
|
14163
|
+
'ghosty image edit URL "change" [--ref URL]... [--text T] [--variants N] [--size 2K] [--aspect 16:9] [--tenant ID] [--out FILE]'
|
|
14164
|
+
],
|
|
14093
14165
|
flags: [
|
|
14094
|
-
["--ref URL", "a reference
|
|
14095
|
-
["--
|
|
14166
|
+
["--ref URL", "a character/object reference (https; JPEG, PNG, WebP, GIF or SVG); repeat it, up to 6. The image KEEPS that character or object (mascot, logo, product)"],
|
|
14167
|
+
["--style-ref URL", "a style reference (up to 3): only its technique, palette and lighting are borrowed, not its content"],
|
|
14168
|
+
["--scene URL", "a background/scene to use (up to 2)"],
|
|
14169
|
+
["--text T", 'exact text to render inside the image ("-50 %", "$299"), up to 200 characters'],
|
|
14170
|
+
["--direction D", "an art direction; repeat it (up to 4) to get one image per direction and pick one"],
|
|
14171
|
+
["--variants N", "how many options (1-4); each one is charged as an image"],
|
|
14172
|
+
["--size SIZE", "1K, 2K (default) or 4K; 4K costs more"],
|
|
14173
|
+
["--aspect RATIO", "1:1, 2:3, 3:2, 3:4, 4:3, 4:5, 5:4, 9:16, 16:9 or 21:9 (edit: omit it to keep the original's)"],
|
|
14096
14174
|
["--tenant ID", "the business (externalId) it is for: it goes to the usage breakdown and to its optional daily cap"],
|
|
14097
14175
|
["--agent SLUG", "which partner agent it is charged to in the breakdown (default: the main one)"],
|
|
14098
|
-
["--out FILE", "also download the PNG here"]
|
|
14176
|
+
["--out FILE", "also download the PNG here (several: FILE-1.png, FILE-2.png\u2026)"]
|
|
14099
14177
|
],
|
|
14100
14178
|
examples: [
|
|
14101
14179
|
'ghosty image generate "our mascot dressed as a pumpkin in a Halloween scene, flat illustration, no text" --ref https://example.com/mascot.svg --aspect 16:9 --tenant org_123',
|
|
14102
|
-
'ghosty image
|
|
14180
|
+
'ghosty image edit https://img.ghosty.studio/u/x/promo.png "add a big red badge in the top right corner" --text "-50 %"',
|
|
14181
|
+
'ghosty image generate "a cozy spa with candles, warm light" --direction "flat illustration with thick outlines" --direction "warm studio photo" --out spa.png'
|
|
14103
14182
|
],
|
|
14104
14183
|
notes: [
|
|
14105
|
-
|
|
14184
|
+
"Use edit (not generate) to change an image that already exists: the result is the same image with only that change.",
|
|
14185
|
+
`Each image is charged apart: USD 0.25 at 1K/2K and USD 0.45 at 4K from the partner space's balance; variants are charged one by one and failed ones are not charged. Without balance: 402. gs sets no cap of its own; a business can have one: tenants set <id> --config '{"imageDailyCap":20}'.`,
|
|
14106
14186
|
"Auth: your login (space owner; --workspace if you have several) or the partner server credential in the env (GHOSTY_PARTNER_KEY + GHOSTY_PARTNER_KEY_SECRET), which then requires --tenant."
|
|
14107
14187
|
],
|
|
14108
14188
|
learn: `${DOCS}/partners#imagenes-con-ia`
|
|
@@ -14469,8 +14549,8 @@ HELPS.novedades = {
|
|
|
14469
14549
|
learn: `${REF}#soporte`
|
|
14470
14550
|
};
|
|
14471
14551
|
HELPS.spaces = {
|
|
14472
|
-
summary: "Workspaces: create one of your own (trial), list yours (or, staff, anyone's), and Ghosty staff operations \u2014 join/leave a client's workspace, change its combo, move \xABpaid until\xBB, rename its slug, change its owner \u2014 and, owner or staff, archive or restore it. Each change is logged in the workspace's audit.",
|
|
14473
|
-
usage: ["ghosty spaces ls [--user EMAIL]", "ghosty spaces create <slug> [--combo teams|sales|both|none] [--dry-run]", "ghosty spaces join|leave <workspace>", "ghosty spaces set <workspace> --combo teams|sales|both|none | --model-cap 0.25|1|4|none | --house-claude on|off [--dry-run]", "ghosty spaces renew <workspace> --until YYYY-MM-DD [--note TEXT] [--dry-run] [--yes]", "ghosty spaces rename <old> <new> [--dry-run] [--yes]", "ghosty spaces archive|restore <workspace> [--dry-run] [--yes]", "ghosty spaces transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] [--yes]", "ghosty spaces log <workspace> [--since 30d] [--action workspace] [--limit N]", "ghosty spaces members ls|add|rm <workspace> [email,\u2026] [--role member|admin|collaborator] [--room ROOM] [--cap N|none] [--until 2026-10-28|14d] [--yes]"],
|
|
14552
|
+
summary: "Workspaces: create one of your own (trial), list yours (or, staff, anyone's), and Ghosty staff operations \u2014 join/leave a client's workspace, change its combo or plan, move \xABpaid until\xBB, rename its slug, change its owner \u2014 and, owner or staff, archive or restore it. Each change is logged in the workspace's audit.",
|
|
14553
|
+
usage: ["ghosty spaces ls [--user EMAIL]", "ghosty spaces create <slug> [--combo teams|sales|both|none] [--dry-run]", "ghosty spaces join|leave <workspace>", "ghosty spaces set <workspace> --combo teams|sales|both|none | --model-cap 0.25|1|4|none | --house-claude on|off [--dry-run]", "ghosty spaces renew <workspace> --until YYYY-MM-DD [--note TEXT] [--dry-run] [--yes]", "ghosty spaces plan <workspace> trial|pro|empresarial [--courtesy] [--until YYYY-MM-DD] [--note TEXT] [--dry-run] [--yes]", "ghosty spaces rename <old> <new> [--dry-run] [--yes]", "ghosty spaces archive|restore <workspace> [--dry-run] [--yes]", "ghosty spaces transfer <workspace> --to EMAIL [--keep-as admin|member|none] [--copy-keys] [--dry-run] [--yes]", "ghosty spaces log <workspace> [--since 30d] [--action workspace] [--limit N]", "ghosty spaces members ls|add|rm <workspace> [email,\u2026] [--role member|admin|collaborator] [--room ROOM] [--cap N|none] [--until 2026-10-28|14d] [--yes]"],
|
|
14474
14554
|
flags: [
|
|
14475
14555
|
["--user EMAIL", "ls (staff): that person's workspaces"],
|
|
14476
14556
|
["--role R", "members add: member (default: boards + editor of the workspace's agents, no keys, billing or transfers) | admin (also invites and removes people) | collaborator (invited to ONE Teams room: no seat, no personal agent)"],
|
|
@@ -14480,8 +14560,9 @@ HELPS.spaces = {
|
|
|
14480
14560
|
["--combo C", "set (staff): teams | sales | both | none (neither Teams nor Sales) \u2014 without Sales its boards exist but nobody sees them; create: other than teams, staff only"],
|
|
14481
14561
|
["--model-cap X", "set (staff): the most expensive model the workspace can pick \u2014 0.25 economy, 1 standard (Sonnet), 4 everything; none = its plan's"],
|
|
14482
14562
|
["--house-claude on|off", "set (staff): its agents run on Ghosty's Claude when the owner brings no key; recycles their Claude boxes"],
|
|
14483
|
-
["--until DATE", "renew: the new \xABpaid until\xBB (YYYY-MM-DD)"],
|
|
14484
|
-
["--note TEXT", "renew: why (goes into the audit)"],
|
|
14563
|
+
["--until DATE", "renew, plan: the new \xABpaid until\xBB (YYYY-MM-DD); plan without it keeps the current one"],
|
|
14564
|
+
["--note TEXT", "renew, plan: why (goes into the audit)"],
|
|
14565
|
+
["--courtesy", "plan (staff): mark it as a no-charge courtesy (written to the workspace's plan note and the audit)"],
|
|
14485
14566
|
["--to EMAIL", "transfer: the new owner (if they have no account it is pre-created and claimed on login)"],
|
|
14486
14567
|
["--keep-as R", "transfer: the previous owner's role \u2014 admin | member (default) | none (removed)"],
|
|
14487
14568
|
["--copy-keys", "transfer: copy the previous owner's provider keys and the connectors its agents use (MercadoPago, Skydropx\u2026) that the new one lacks. Only the owner changes: documents, databases, boards and numbers its agents use move with it; anything also used outside the space stays and is listed"],
|
|
@@ -14489,8 +14570,8 @@ HELPS.spaces = {
|
|
|
14489
14570
|
["-n, --dry-run", "show what changes, change nothing"],
|
|
14490
14571
|
["--yes", "skip the confirmation (required without a terminal)"]
|
|
14491
14572
|
],
|
|
14492
|
-
examples: ["ghosty spaces ls", "ghosty spaces create mailmask --dry-run", "ghosty spaces ls --user brenda@siiqtec.com", "ghosty spaces join denik", "ghosty spaces set denik --combo sales --dry-run", "ghosty spaces set mailmask --model-cap 4 --house-claude on", 'ghosty spaces renew descti --until 2026-11-01 --note "pag\xF3 octubre"', "ghosty spaces rename totequim siiqtec --dry-run", "ghosty spaces archive box-xfer-test --dry-run", "ghosty spaces transfer siiqtec --to siiqtec@gmail.com --keep-as admin --copy-keys --dry-run", "ghosty spaces log siiqtec --since 30d", "ghosty spaces members add business chrome-review@ghosty.studio --until 14d", "ghosty spaces members rm business chrome-review@ghosty.studio --yes"],
|
|
14493
|
-
notes: ["create follows the same rules as the web: you own it, it starts as a 30-day trial, your email must be confirmed, and your plan caps how many you own. Next: ghosty partner enable <slug>.", "With a Stripe subscription renew refuses: the paid invoice moves the date.", "rename changes only the slug (id and namespace stay, so board, Stripe and WhatsApp keep working); old <slug>.sales links stop working.", "archive does what Settings \u2192 Archive does: the workspace leaves /app and spaces ls, its agents and data stay; it asks you to type the slug. Undo: ghosty spaces restore <slug>. Logged as workspace.archive / workspace.restore.", "transfer moves the agents with the workspace: ACP boxes move to the new owner with their /data, pool boxes are recycled (the owner is baked into the box); without --copy-keys the dry run lists which keys the new owner lacks \u2014 those agents would stop answering."],
|
|
14573
|
+
examples: ["ghosty spaces ls", "ghosty spaces create mailmask --dry-run", "ghosty spaces ls --user brenda@siiqtec.com", "ghosty spaces join denik", "ghosty spaces set denik --combo sales --dry-run", "ghosty spaces set mailmask --model-cap 4 --house-claude on", 'ghosty spaces renew descti --until 2026-11-01 --note "pag\xF3 octubre"', "ghosty spaces plan business pro --courtesy --dry-run", "ghosty spaces rename totequim siiqtec --dry-run", "ghosty spaces archive box-xfer-test --dry-run", "ghosty spaces transfer siiqtec --to siiqtec@gmail.com --keep-as admin --copy-keys --dry-run", "ghosty spaces log siiqtec --since 30d", "ghosty spaces members add business chrome-review@ghosty.studio --until 14d", "ghosty spaces members rm business chrome-review@ghosty.studio --yes"],
|
|
14574
|
+
notes: ["create follows the same rules as the web: you own it, it starts as a 30-day trial, your email must be confirmed, and your plan caps how many you own. Next: ghosty partner enable <slug>.", "With a Stripe subscription renew refuses: the paid invoice moves the date.", "plan applies the same rules as Plan and billing in /admin/tenants: trial \u2192 pro lifts the out-of-balance cut and the trial expiry, raises the model cap 0.25\xD7 \u2192 1\xD7 and measures tokens by calendar month. It never charges Stripe nor emails the customer; the dry run shows plan, model cap, tokens and \xABpaid until\xBB before \u2192 after. Logged as workspace.plan.", "rename changes only the slug (id and namespace stay, so board, Stripe and WhatsApp keep working); old <slug>.sales links stop working.", "archive does what Settings \u2192 Archive does: the workspace leaves /app and spaces ls, its agents and data stay; it asks you to type the slug. Undo: ghosty spaces restore <slug>. Logged as workspace.archive / workspace.restore.", "transfer moves the agents with the workspace: ACP boxes move to the new owner with their /data, pool boxes are recycled (the owner is baked into the box); without --copy-keys the dry run lists which keys the new owner lacks \u2014 those agents would stop answering."],
|
|
14494
14575
|
learn: `${REF}#espacios`
|
|
14495
14576
|
};
|
|
14496
14577
|
HELPS.workspaces = HELPS.spaces;
|
|
@@ -15216,8 +15297,8 @@ var PACK = { year: { usd: 49, mxn: 990 }, month: { usd: 5, mxn: 99 } };
|
|
|
15216
15297
|
var packPrice = (c, i, lang2) => `$${(PACK[i]?.[c] ?? 0).toLocaleString("en-US")} ${c.toUpperCase()}${lang2 === "es" ? i === "year" ? " al a\xF1o" : " al mes" : i === "year" ? "/yr" : "/mo"}`;
|
|
15217
15298
|
var kb = (n) => n ? `${Math.max(1, Math.round(n / 1024))} KB` : "";
|
|
15218
15299
|
var day = (iso) => iso ? iso.slice(0, 10) : "";
|
|
15219
|
-
async function sitesCmd(sub, a1, a2, v) {
|
|
15220
|
-
const ex = "ghosty sites ls [--house] \xB7 pin|unpin <slug|id> \xB7 pins [--cancel|--resume] \xB7 search <slug|id> [--days 28] \xB7 publish <file.html|folder> [--title T] [--slug S] [--site <slug|id>] \xB7 slug <slug|id> <new-slug>";
|
|
15300
|
+
async function sitesCmd(sub, a1, a2, v, a3) {
|
|
15301
|
+
const ex = "ghosty sites ls [--house] \xB7 pin|unpin <slug|id> \xB7 pins [--cancel|--resume] \xB7 search <slug|id> [--days 28] \xB7 domain [ls|add|verify|rm] <slug> [domain] \xB7 publish <file.html|folder> [--title T] [--slug S] [--site <slug|id>] \xB7 slug <slug|id> <new-slug>";
|
|
15221
15302
|
switch (sub ?? "ls") {
|
|
15222
15303
|
case "ls":
|
|
15223
15304
|
case "list": {
|
|
@@ -15274,6 +15355,9 @@ ${table(r.pinned.map((p) => ({ slug: p.slug, title: (p.title ?? "").slice(0, 40)
|
|
|
15274
15355
|
].join("\n")
|
|
15275
15356
|
);
|
|
15276
15357
|
}
|
|
15358
|
+
case "domain":
|
|
15359
|
+
case "domains":
|
|
15360
|
+
return domainCmd(a1, a2, a3);
|
|
15277
15361
|
case "publish":
|
|
15278
15362
|
case "deploy": {
|
|
15279
15363
|
if (!a1) throw usage(t("Missing the file or folder.", "Falta el archivo o la carpeta."), ex);
|
|
@@ -15300,6 +15384,41 @@ ${dim(t("Links with the old slug may stop working.", "Las ligas con el slug viej
|
|
|
15300
15384
|
throw usage(t(`Unknown sites subcommand: ${sub}.`, `Subcomando de sites desconocido: ${sub}.`), ex);
|
|
15301
15385
|
}
|
|
15302
15386
|
}
|
|
15387
|
+
function domainLine(r, lang2 = "es") {
|
|
15388
|
+
if (r.verified) {
|
|
15389
|
+
return r.applied === false ? lang2 === "es" ? `Verificado; la app se est\xE1 levantando y queda en ${r.url} en 1\u20133 min.` : `Verified; the app is starting and will be at ${r.url} in 1\u20133 min.` : lang2 === "es" ? `Listo: ${r.url} ya sirve la app (HTTPS sale solo con la primera visita).` : `Done: ${r.url} serves the app (HTTPS is issued on the first visit).`;
|
|
15390
|
+
}
|
|
15391
|
+
const rec = `${r.dns.type} ${r.dns.name} \u2192 ${r.dns.value}`;
|
|
15392
|
+
return lang2 === "es" ? `Pon este registro en tu proveedor de DNS: ${rec}${r.reason ? `
|
|
15393
|
+
(${r.reason})` : ""}
|
|
15394
|
+
Luego: ghosty sites domain verify <slug> ${r.host}` : `Add this record at your DNS provider: ${rec}${r.reason ? `
|
|
15395
|
+
(${r.reason})` : ""}
|
|
15396
|
+
Then: ghosty sites domain verify <slug> ${r.host}`;
|
|
15397
|
+
}
|
|
15398
|
+
async function domainCmd(action, a2, a3) {
|
|
15399
|
+
const ex = "ghosty sites domain [ls] <slug> \xB7 add|verify|rm <slug> <domain>";
|
|
15400
|
+
const acts = /* @__PURE__ */ new Set(["ls", "list", "add", "verify", "rm", "remove"]);
|
|
15401
|
+
const [act, slug, host] = action && !acts.has(action) ? ["ls", action, a2] : [action ?? "ls", a2, a3];
|
|
15402
|
+
if (!slug) throw usage(t("Missing the app (slug, id or URL).", "Falta la app (slug, id o URL)."), ex);
|
|
15403
|
+
const path = `/api/v2/sites/${encodeURIComponent(slug)}/domain`;
|
|
15404
|
+
if (act === "ls" || act === "list") {
|
|
15405
|
+
const r2 = await api(path);
|
|
15406
|
+
return out(
|
|
15407
|
+
r2,
|
|
15408
|
+
() => r2.domains.length ? `${bold(r2.url)}
|
|
15409
|
+
${table(r2.domains.map((d) => ({ domain: d.host, state: d.verified ? t("verified", "verificado") : t("waiting for DNS", "esperando DNS"), dns: `${d.dns.type} \u2192 ${d.dns.value}` })), ["domain", "state", "dns"])}` : t(`${r2.url} has no custom domain. Add one: ghosty sites domain add ${r2.slug} app.yourdomain.com`, `${r2.url} no tiene dominio propio. Agrega uno: ghosty sites domain add ${r2.slug} app.tudominio.com`)
|
|
15410
|
+
);
|
|
15411
|
+
}
|
|
15412
|
+
if (!host) throw usage(t("Missing the domain.", "Falta el dominio."), ex);
|
|
15413
|
+
if (act === "rm" || act === "remove") {
|
|
15414
|
+
const r2 = await api(path, { method: "DELETE", body: { domain: host } });
|
|
15415
|
+
return out(r2, () => `${lavender("\u2713")} ${t("Removed", "Quitado")} ${bold(r2.host)}`);
|
|
15416
|
+
}
|
|
15417
|
+
if (act !== "add" && act !== "verify") throw usage(t(`Unknown domain action: ${act}.`, `Acci\xF3n de dominio desconocida: ${act}.`), ex);
|
|
15418
|
+
const r = await api(path, { method: "POST", body: { domain: host, ...act === "verify" ? { verify: true } : {} } });
|
|
15419
|
+
return out(r, () => `${r.verified ? lavender("\u2713") : dim("\u2026")} ${bold(r.host)}
|
|
15420
|
+
${domainLine(r, t("en", "es") === "es" ? "es" : "en").replace("<slug>", slug)}`);
|
|
15421
|
+
}
|
|
15303
15422
|
|
|
15304
15423
|
// src/commands/docs.ts
|
|
15305
15424
|
init_api();
|
|
@@ -16153,6 +16272,58 @@ async function settingsCmd(sub, key, value) {
|
|
|
16153
16272
|
throw usage(t(`Unknown settings subcommand: ${sub}.`, `Subcomando de settings desconocido: ${sub}.`), "ghosty settings ls|set|unset <KEY> [value]");
|
|
16154
16273
|
}
|
|
16155
16274
|
|
|
16275
|
+
// src/commands/coupons.ts
|
|
16276
|
+
init_api();
|
|
16277
|
+
init_i18n();
|
|
16278
|
+
init_util();
|
|
16279
|
+
function couponRow(c) {
|
|
16280
|
+
return {
|
|
16281
|
+
code: c.code,
|
|
16282
|
+
credit: `$${c.creditMxn}`,
|
|
16283
|
+
plan: c.plan ?? "",
|
|
16284
|
+
until: c.until ? c.until.slice(0, 10) : "",
|
|
16285
|
+
used: `${c.redemptions}/${c.maxRedemptions ?? "\u221E"}`,
|
|
16286
|
+
state: c.active ? t("active", "activo") : t("draft", "borrador"),
|
|
16287
|
+
only: c.eligibility ?? "",
|
|
16288
|
+
agent: c.agentId ?? "",
|
|
16289
|
+
note: c.note ?? ""
|
|
16290
|
+
};
|
|
16291
|
+
}
|
|
16292
|
+
function bodyOf(v) {
|
|
16293
|
+
const b = {};
|
|
16294
|
+
if (v.credit !== void 0) b.creditMxn = Number(v.credit);
|
|
16295
|
+
if (v.plan !== void 0) b.plan = v.plan === "none" ? null : v.plan;
|
|
16296
|
+
if (v.until !== void 0) b.until = v.until;
|
|
16297
|
+
if (v.max !== void 0) b.maxRedemptions = v.max === "none" ? null : Number(v.max);
|
|
16298
|
+
if (v.on) b.active = true;
|
|
16299
|
+
if (v.off) b.active = false;
|
|
16300
|
+
if (v.note !== void 0) b.note = v.note;
|
|
16301
|
+
if (v.eligibility !== void 0) b.eligibility = v.eligibility;
|
|
16302
|
+
if (v.agent !== void 0) b.agentId = v.agent;
|
|
16303
|
+
return b;
|
|
16304
|
+
}
|
|
16305
|
+
async function couponsCmd(sub, code, v) {
|
|
16306
|
+
const one = (c) => `${lavender("\u2713")} ${c.code} $${c.creditMxn}${c.plan ? ` + ${c.plan} \u2192 ${c.until?.slice(0, 10)}` : ""} ${c.active ? t("active", "activo") : dim(t("draft", "borrador"))}`;
|
|
16307
|
+
if (!sub || sub === "ls" || sub === "list") {
|
|
16308
|
+
const r = await api("/api/v2/support/coupons");
|
|
16309
|
+
return out(r, () => r.coupons.length ? table(r.coupons.map(couponRow), ["code", "credit", "plan", "until", "used", "state", "only", "agent", "note"]) : dim(t("No coupons.", "Sin cupones.")));
|
|
16310
|
+
}
|
|
16311
|
+
if (!code) throw usage(t("Missing the coupon code.", "Falta el c\xF3digo del cup\xF3n."), `ghosty coupons ${sub} <CODE>`);
|
|
16312
|
+
if (sub === "create") {
|
|
16313
|
+
const r = await api("/api/v2/support/coupons", { method: "POST", body: { code, ...bodyOf(v) } });
|
|
16314
|
+
return out(r, () => one(r.coupon));
|
|
16315
|
+
}
|
|
16316
|
+
if (sub === "set") {
|
|
16317
|
+
const r = await api(`/api/v2/support/coupons/${encodeURIComponent(code)}`, { method: "PATCH", body: bodyOf(v) });
|
|
16318
|
+
return out(r, () => one(r.coupon));
|
|
16319
|
+
}
|
|
16320
|
+
if (sub === "redeem") {
|
|
16321
|
+
const r = await api("/api/v2/me/coupons", { method: "POST", body: { code } });
|
|
16322
|
+
return out(r, () => `${lavender("\u2713")} ${r.message}`);
|
|
16323
|
+
}
|
|
16324
|
+
throw usage(t(`Unknown coupons subcommand: ${sub}.`, `Subcomando de coupons desconocido: ${sub}.`), "ghosty coupons ls|create|set|redeem <CODE>");
|
|
16325
|
+
}
|
|
16326
|
+
|
|
16156
16327
|
// src/commands/ads.ts
|
|
16157
16328
|
init_api();
|
|
16158
16329
|
init_i18n();
|
|
@@ -16486,6 +16657,7 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
16486
16657
|
spaces join|leave <workspace> Enter or leave a client's workspace as staff (no seat; logged)
|
|
16487
16658
|
spaces set <workspace> --combo sales teams | sales | both | none (without Sales its boards are invisible) [--model-cap 0.25|1|4|none: most expensive model] [--house-claude on|off]
|
|
16488
16659
|
spaces renew <workspace> --until DATE Move \xABpaid until\xBB (logged) [--note] [--dry-run]
|
|
16660
|
+
spaces plan <workspace> trial|pro|empresarial Change its plan, same rules as /admin/tenants; no Stripe charge, no email (logged) [--courtesy] [--until DATE] [--note] [--dry-run]
|
|
16489
16661
|
spaces rename <old> <new> Change its slug only [--dry-run]
|
|
16490
16662
|
spaces archive|restore <workspace> Archive it (out of /app and spaces ls; agents and data stay) or bring it back (owner or staff) [--dry-run]
|
|
16491
16663
|
spaces transfer <workspace> --to EMAIL New owner; agents go with it (ACP boxes move with their /data, pool boxes are recycled) [--keep-as admin|member|none] [--copy-keys] [--dry-run]
|
|
@@ -16495,6 +16667,8 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
16495
16667
|
staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
|
|
16496
16668
|
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]
|
|
16497
16669
|
settings ls|set|unset <KEY> [value] Platform switches (staff): who answers /c without an account, native subagents\u2026 [+id/-id edits a list]
|
|
16670
|
+
coupons ls|create|set <CODE> Redeemable coupons (staff): balance in cost pesos and an optional lent plan until a date; created as a draft [--credit 50] [--plan pro|power|max --until 2026-11-13] [--max 100] [--eligibility hackathon:<event>: accepted people only] [--agent ID: each account gets its own copy] [--on|--off] [--note]
|
|
16671
|
+
coupons redeem <CODE> Redeem a coupon for your account (also /canjear?codigo=CODE)
|
|
16498
16672
|
ads watch [ls|run] Campaign watch (staff): Meta campaigns that stop delivering and ads-only WhatsApp numbers with no leads for 24 h [run --dry-run: what it would alert]
|
|
16499
16673
|
audit ls The audit log: who changed what (agent page, channels, pauses, replies, transfers, "log in as") [--workspace SLUG] [--agent ID] [--actor EMAIL] [--action A] [--since 24h] [--limit N]
|
|
16500
16674
|
factory rooms ls|repos|connect|disconnect Set up the factory for a repo without opening Teams: create a room and connect the repo to it [connect owner/repo --room R --create]
|
|
@@ -16598,6 +16772,7 @@ ${bold("Sites")} ${dim("(sites your agents publish at <slug>.ghosty.page)")}
|
|
|
16598
16772
|
sites pin <slug|id> Pin it: never pauses, no banner ($49 USD/yr or $5/mo, includes up to 3 sites) [--interval year|month] [--currency usd|mxn] [--add-pack: 3 more]
|
|
16599
16773
|
sites unpin <slug|id> Release its slot (back to the Free rule: 30 days + notice)
|
|
16600
16774
|
sites search <slug|id> How Google finds it: clicks, impressions, searches, indexed or not [--days 28]
|
|
16775
|
+
sites domain add|verify|rm <slug> <dom> Custom domain for an app (DNS record \u2192 verify \u2192 HTTPS) [ls <slug>: list]
|
|
16601
16776
|
sites pins Your pinned-sites subscription and slots [--cancel | --resume]
|
|
16602
16777
|
sites publish <file.html|folder> Publish a house site (staff): no owner, no expiry, no banner [--title] [--slug S] [--site <slug|id>: update that one]
|
|
16603
16778
|
sites slug <slug|id> <new-slug> Change a site's slug (staff)
|
|
@@ -16640,7 +16815,8 @@ ${bold("Browser")} ${dim("(Ghosty for Chrome)")}
|
|
|
16640
16815
|
|
|
16641
16816
|
${bold("Partners")} ${dim("(give an agent to each of YOUR customers \u2014 see: ghosty partner --help)")}
|
|
16642
16817
|
partner ls | enable | credentials | agent | tenants | audit | try
|
|
16643
|
-
image generate "prompt" An AI image for your businesses, charged to the space's balance [--ref URL (repeat, keeps the character)] [--aspect 16:9] [--tenant ID] [--out FILE]
|
|
16818
|
+
image generate "prompt" An AI image for your businesses, charged to the space's balance [--ref URL (repeat, keeps the character)] [--style-ref URL] [--scene URL] [--text "-50 %"] [--direction D]\u2026 [--variants N] [--size 1K|2K|4K] [--aspect 16:9] [--tenant ID] [--out FILE]
|
|
16819
|
+
image edit URL "change" Edit an existing image: only that change, the rest stays [--ref URL] [--text T] [--variants N] [--size] [--aspect] [--tenant ID] [--out FILE]
|
|
16644
16820
|
|
|
16645
16821
|
${bold("Your account")}
|
|
16646
16822
|
me files ls|get|export|upload|rm Files in your account [--q TEXT] [--kind image|video|audio|document|other] [--cursor C] \xB7 get <id> [--out FILE]
|
|
@@ -16689,6 +16865,7 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
16689
16865
|
spaces join|leave <espacio> Entra o sal del espacio de un cliente como staff (sin asiento; queda en bit\xE1cora)
|
|
16690
16866
|
spaces set <espacio> --combo sales teams | sales | both | none (sin Ventas sus tableros no se ven) [--model-cap 0.25|1|4|none: el modelo m\xE1s caro] [--house-claude on|off]
|
|
16691
16867
|
spaces renew <espacio> --until FECHA Mueve \xABpagado hasta\xBB (queda en bit\xE1cora) [--note] [--dry-run]
|
|
16868
|
+
spaces plan <espacio> trial|pro|empresarial Cambia su plan, mismas reglas que /admin/tenants; sin cobro en Stripe ni correo (queda en bit\xE1cora) [--courtesy] [--until FECHA] [--note] [--dry-run]
|
|
16692
16869
|
spaces rename <viejo> <nuevo> Cambia s\xF3lo su slug [--dry-run]
|
|
16693
16870
|
spaces archive|restore <espacio> Arch\xEDvalo (sale de /app y de spaces ls; agentes y datos se quedan) o tr\xE1elo de vuelta (due\xF1o o staff) [--dry-run]
|
|
16694
16871
|
spaces transfer <espacio> --to CORREO Due\xF1o nuevo; los agentes se van con \xE9l (las cajas ACP se mudan con su /data, las del pool se reciclan) [--keep-as admin|member|none] [--copy-keys] [--dry-run]
|
|
@@ -16698,6 +16875,8 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
16698
16875
|
staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
|
|
16699
16876
|
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]
|
|
16700
16877
|
settings ls|set|unset <CLAVE> [valor] Perillas de la plataforma (staff): qui\xE9n atiende /c sin cuenta, subagentes nativos\u2026 [+id/-id edita una lista]
|
|
16878
|
+
coupons ls|create|set <C\xD3DIGO> Cupones canjeables (staff): saldo en pesos de costo y un plan prestado opcional hasta una fecha; nacen como borrador [--credit 50] [--plan pro|power|max --until 2026-11-13] [--max 100] [--eligibility hackathon:<evento>: s\xF3lo aceptados] [--agent ID: cada cuenta recibe su copia] [--on|--off] [--note]
|
|
16879
|
+
coupons redeem <C\xD3DIGO> Canjea un cup\xF3n para tu cuenta (tambi\xE9n /canjear?codigo=C\xD3DIGO)
|
|
16701
16880
|
ads watch [ls|run] Vig\xEDa de campa\xF1as (staff): campa\xF1as de Meta que dejan de entregar y n\xFAmeros \xABs\xF3lo anuncios\xBB sin leads en 24 h [run --dry-run: lo que avisar\xEDa]
|
|
16702
16881
|
audit ls La bit\xE1cora: qui\xE9n cambi\xF3 qu\xE9 (ficha, canales, pausas, respuestas, traspasos, \xABentrar como\xBB) [--workspace SLUG] [--agent ID] [--actor CORREO] [--action A] [--since 24h] [--limit N]
|
|
16703
16882
|
factory rooms ls|repos|connect|disconnect Deja lista la f\xE1brica de un repo sin abrir Teams: crea un room y con\xE9ctale el repo [connect due\xF1o/repo --room R --create]
|
|
@@ -16801,6 +16980,7 @@ ${bold("Sitios")} ${dim("(los sitios que publican tus agentes en <slug>.ghosty.
|
|
|
16801
16980
|
sites pin <slug|id> F\xEDjalo: no se pausa y va sin franja ($49 USD al a\xF1o o $5 al mes, incluye hasta 3 sitios) [--interval year|month] [--currency usd|mxn] [--add-pack: 3 m\xE1s]
|
|
16802
16981
|
sites unpin <slug|id> Suelta su lugar (vuelve a la regla Gratis: 30 d\xEDas + aviso)
|
|
16803
16982
|
sites pins Tu suscripci\xF3n de Sitios fijos y sus lugares [--cancel | --resume]
|
|
16983
|
+
sites domain add|verify|rm <slug> <dom> Dominio propio para una app (registro DNS \u2192 verificar \u2192 HTTPS) [ls <slug>: lista]
|
|
16804
16984
|
sites publish <archivo.html|carpeta> Publica un sitio de la casa (staff): sin due\xF1o, sin caducidad, sin franja [--title] [--slug S] [--site <slug|id>: actualiza \xE9se]
|
|
16805
16985
|
sites slug <slug|id> <slug-nuevo> Cambia el slug de un sitio (staff)
|
|
16806
16986
|
|
|
@@ -16842,7 +17022,8 @@ ${bold("Navegador")} ${dim("(Ghosty para Chrome)")}
|
|
|
16842
17022
|
|
|
16843
17023
|
${bold("Partners")} ${dim("(dale un agente a cada uno de TUS clientes \u2014 ver: ghosty partner --help)")}
|
|
16844
17024
|
partner ls | enable | credentials | agent | tenants | audit | try
|
|
16845
|
-
image generate "prompt" Una imagen con IA para tus negocios, cobrada del saldo del espacio [--ref URL (se repite, conserva al personaje)] [--aspect 16:9] [--tenant ID] [--out ARCHIVO]
|
|
17025
|
+
image generate "prompt" Una imagen con IA para tus negocios, cobrada del saldo del espacio [--ref URL (se repite, conserva al personaje)] [--style-ref URL] [--scene URL] [--text "-50 %"] [--direction D]\u2026 [--variants N] [--size 1K|2K|4K] [--aspect 16:9] [--tenant ID] [--out ARCHIVO]
|
|
17026
|
+
image edit URL "cambio" Edita una imagen que ya existe: s\xF3lo ese cambio, lo dem\xE1s se queda [--ref URL] [--text T] [--variants N] [--size] [--aspect] [--tenant ID] [--out ARCHIVO]
|
|
16846
17027
|
|
|
16847
17028
|
${bold("Tu cuenta")}
|
|
16848
17029
|
me files ls|get|export|upload|rm Archivos de tu cuenta [--q TEXTO] [--kind image|video|audio|document|other] [--cursor C] \xB7 get <id> [--out ARCHIVO]
|
|
@@ -16868,7 +17049,7 @@ ${bold("Opciones globales")}
|
|
|
16868
17049
|
${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorrecto \xB7 3 sin sesi\xF3n
|
|
16869
17050
|
${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.")}
|
|
16870
17051
|
${dim("Documentaci\xF3n: https://www.ghosty.studio/docs/cli")}`;
|
|
16871
|
-
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "settings", "ads", "audit", "factory", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "teams", "partner", "image", "me", "channels", "board", "boards", "access", "credentials", "connectors", "browser", "support", "docs", "help"];
|
|
17052
|
+
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "settings", "coupons", "ads", "audit", "factory", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "teams", "partner", "image", "me", "channels", "board", "boards", "access", "credentials", "connectors", "browser", "support", "docs", "help"];
|
|
16872
17053
|
var AGENTS_SUBS = ["ls", "create", "get", "show", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "embed", "box", "token", "memory", "transfer"];
|
|
16873
17054
|
function unknown(what, input, known, helpCmd) {
|
|
16874
17055
|
const s2 = suggest(input, known);
|
|
@@ -16934,6 +17115,8 @@ async function main() {
|
|
|
16934
17115
|
in: { type: "string" },
|
|
16935
17116
|
every: { type: "string" },
|
|
16936
17117
|
until: { type: "string" },
|
|
17118
|
+
credit: { type: "string" },
|
|
17119
|
+
eligibility: { type: "string" },
|
|
16937
17120
|
title: { type: "string" },
|
|
16938
17121
|
body: { type: "string" },
|
|
16939
17122
|
profile: { type: "string" },
|
|
@@ -17012,6 +17195,7 @@ async function main() {
|
|
|
17012
17195
|
like: { type: "string" },
|
|
17013
17196
|
"copy-dbs": { type: "boolean" },
|
|
17014
17197
|
"copy-keys": { type: "boolean" },
|
|
17198
|
+
courtesy: { type: "boolean" },
|
|
17015
17199
|
"keep-as": { type: "string" },
|
|
17016
17200
|
"no-notify": { type: "boolean" },
|
|
17017
17201
|
board: { type: "string" },
|
|
@@ -17138,6 +17322,11 @@ async function main() {
|
|
|
17138
17322
|
"ads-only": { type: "string" },
|
|
17139
17323
|
"partner-tenant": { type: "string" },
|
|
17140
17324
|
ref: { type: "string", multiple: true },
|
|
17325
|
+
"style-ref": { type: "string", multiple: true },
|
|
17326
|
+
scene: { type: "string", multiple: true },
|
|
17327
|
+
direction: { type: "string", multiple: true },
|
|
17328
|
+
variants: { type: "string" },
|
|
17329
|
+
size: { type: "string" },
|
|
17141
17330
|
aspect: { type: "string" },
|
|
17142
17331
|
tenant: { type: "string" },
|
|
17143
17332
|
"app-id": { type: "string" },
|
|
@@ -17173,7 +17362,7 @@ async function main() {
|
|
|
17173
17362
|
const tokens = splitTokens(pos, v);
|
|
17174
17363
|
globals.token = tokens.session;
|
|
17175
17364
|
globals.profile = v.profile;
|
|
17176
|
-
if (v.version) return out({ version: "0.
|
|
17365
|
+
if (v.version) return out({ version: "0.83.0" }, () => "0.83.0");
|
|
17177
17366
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
17178
17367
|
const context = (await readConfig()).workspace;
|
|
17179
17368
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -17276,7 +17465,7 @@ async function main() {
|
|
|
17276
17465
|
return novedadesCmd(sub, a1, v);
|
|
17277
17466
|
case "sites":
|
|
17278
17467
|
case "site":
|
|
17279
|
-
return sitesCmd(sub, a1, a2, v);
|
|
17468
|
+
return sitesCmd(sub, a1, a2, v, pos[4]);
|
|
17280
17469
|
case "board":
|
|
17281
17470
|
return boardCmd(sub, a1, v, a2);
|
|
17282
17471
|
case "boards":
|
|
@@ -17315,7 +17504,7 @@ async function main() {
|
|
|
17315
17504
|
case "partner":
|
|
17316
17505
|
return partnerCmd(sub, a1, a2, { ...v, token: tokens.turn }, pos[4]);
|
|
17317
17506
|
case "image":
|
|
17318
|
-
return imageCmd(sub, a1, v);
|
|
17507
|
+
return imageCmd(sub, a1, a2, v);
|
|
17319
17508
|
case "usage":
|
|
17320
17509
|
if (v.images) return imageUsage(v);
|
|
17321
17510
|
if (v.boxes && v.by === "template") return fleetBoxes();
|
|
@@ -17342,6 +17531,8 @@ async function main() {
|
|
|
17342
17531
|
return staffCmd(sub, a1, a2, v);
|
|
17343
17532
|
case "settings":
|
|
17344
17533
|
return settingsCmd(sub, a1, a2);
|
|
17534
|
+
case "coupons":
|
|
17535
|
+
return couponsCmd(sub, a1, v);
|
|
17345
17536
|
case "ads":
|
|
17346
17537
|
return adsCmd(sub, a1, v);
|
|
17347
17538
|
case "audit":
|
|
@@ -17370,7 +17561,7 @@ async function main() {
|
|
|
17370
17561
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
17371
17562
|
}
|
|
17372
17563
|
}
|
|
17373
|
-
var notice = updateNotice("0.
|
|
17564
|
+
var notice = updateNotice("0.83.0").catch(() => null);
|
|
17374
17565
|
main().then(
|
|
17375
17566
|
async () => {
|
|
17376
17567
|
const n = await notice;
|
package/package.json
CHANGED