@ghostystudio/cli 0.77.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 +356 -45
- 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
|
|
@@ -1264,7 +1264,7 @@ var mteams_exports = {};
|
|
|
1264
1264
|
__export(mteams_exports, {
|
|
1265
1265
|
mteamsCmd: () => mteamsCmd
|
|
1266
1266
|
});
|
|
1267
|
-
import { writeFile as
|
|
1267
|
+
import { writeFile as writeFile8 } from "node:fs/promises";
|
|
1268
1268
|
function list(bots) {
|
|
1269
1269
|
return bots.length ? table(
|
|
1270
1270
|
bots.map((b) => ({
|
|
@@ -1306,7 +1306,7 @@ ${dim(`${t("Next", "Sigue")}: ghosty channels mteams zip ${id} ${b?.id ?? "<bot-
|
|
|
1306
1306
|
const res = await request(`${path}/${enc9(botId)}/zip`);
|
|
1307
1307
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
1308
1308
|
const file = v.out ?? "ghosty-teams.zip";
|
|
1309
|
-
await
|
|
1309
|
+
await writeFile8(file, bytes);
|
|
1310
1310
|
return out({ saved: file, bytes: bytes.length }, () => `${lavender("\u2713")} ${t(`Saved ${file}: upload it in Teams admin \u2192 Manage apps.`, `Se guard\xF3 ${file}: s\xFAbelo en Teams admin \u2192 Administrar apps.`)}`);
|
|
1311
1311
|
}
|
|
1312
1312
|
case "on":
|
|
@@ -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
|
});
|
|
@@ -11482,9 +11514,66 @@ async function partnerCmd(sub, a1, a2, v, a3) {
|
|
|
11482
11514
|
}
|
|
11483
11515
|
}
|
|
11484
11516
|
|
|
11517
|
+
// src/commands/image.ts
|
|
11518
|
+
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
11519
|
+
import { extname as extname2 } from "node:path";
|
|
11520
|
+
init_util();
|
|
11521
|
+
init_i18n();
|
|
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 %"');
|
|
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');
|
|
11536
|
+
const body = {
|
|
11537
|
+
prompt,
|
|
11538
|
+
...base ? { baseImageUrl: base } : {},
|
|
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 } : {},
|
|
11546
|
+
...v.aspect ? { aspectRatio: v.aspect } : {},
|
|
11547
|
+
...v.tenant ? { tenant: { externalId: v.tenant } } : {},
|
|
11548
|
+
...v.agent ? { agent: v.agent } : {}
|
|
11549
|
+
};
|
|
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 = [];
|
|
11553
|
+
if (v.out) {
|
|
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
|
+
}
|
|
11561
|
+
}
|
|
11562
|
+
const how = { edit: t("edited", "editada"), compose: t("composed from references", "compuesta con referencias"), generate: t("generated", "generada") }[r.mode] ?? r.mode;
|
|
11563
|
+
return out(
|
|
11564
|
+
r,
|
|
11565
|
+
() => [
|
|
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}`)}`)
|
|
11570
|
+
].join("\n")
|
|
11571
|
+
);
|
|
11572
|
+
}
|
|
11573
|
+
|
|
11485
11574
|
// src/commands/data.ts
|
|
11486
11575
|
init_api();
|
|
11487
|
-
import { readdir as readdir2, readFile as readFile6, writeFile as
|
|
11576
|
+
import { readdir as readdir2, readFile as readFile6, writeFile as writeFile7 } from "node:fs/promises";
|
|
11488
11577
|
import { basename as basename3, join as join5 } from "node:path";
|
|
11489
11578
|
|
|
11490
11579
|
// src/rows.ts
|
|
@@ -11653,7 +11742,7 @@ async function dbsExport(id, db, v) {
|
|
|
11653
11742
|
const suggested = /filename="([^"]+)"/.exec(res.headers.get("content-disposition") ?? "")?.[1] ?? (format === "csv" ? `${db}-${v.table}.csv` : `${db}.sqlite`);
|
|
11654
11743
|
const file = v.out ?? suggested;
|
|
11655
11744
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
11656
|
-
await
|
|
11745
|
+
await writeFile7(file, bytes);
|
|
11657
11746
|
const countsHeader = res.headers.get("x-gs-row-counts");
|
|
11658
11747
|
const counts = countsHeader ? JSON.parse(Buffer.from(countsHeader, "base64").toString("utf8")) : {};
|
|
11659
11748
|
const rows = Object.entries(counts).map(([tb, n]) => ({ table: tb, rows: n }));
|
|
@@ -11719,6 +11808,19 @@ ${dim(`${t(`${rows.length} row(s)`, `${rows.length} fila(s)`)} \xB7 ${Math.round
|
|
|
11719
11808
|
const rows = r.writes.map((w) => ({ when: w.created_at, agent: w.agent_id.slice(0, 10), channel: w.canal ?? "", what: `${w.op} ${w.table_name}${w.row_id != null ? ` #${w.row_id}` : ""}`, customer: w.phone10 ?? "", why: w.reason ?? "" }));
|
|
11720
11809
|
return out(r, () => rows.length ? table(rows, ["when", "agent", "channel", "what", "customer", "why"]) : dim(t("No agent writes recorded yet in this database.", "Todav\xEDa no hay escrituras de agentes registradas en esta base.")));
|
|
11721
11810
|
}
|
|
11811
|
+
case "checkpoints": {
|
|
11812
|
+
db = need2(db, t("database (id or name)", "la base (id o nombre)"), "ghosty dbs checkpoints <agent-id> <db>");
|
|
11813
|
+
const r = await api(agentPath2(id, `/dbs/${enc8(db)}/checkpoints`));
|
|
11814
|
+
const rows = r.checkpoints.map((c) => ({ id: c.id, when: c.at, rows: Object.values(c.counts).reduce((a, b) => a + b, 0), why: c.reason }));
|
|
11815
|
+
return out(r, () => rows.length ? table(rows, ["id", "when", "rows", "why"]) : dim(t("No checkpoints yet: one is taken before the first write of each agent turn.", "Todav\xEDa no hay checkpoints: se toma uno antes de la primera escritura de cada turno de un agente.")));
|
|
11816
|
+
}
|
|
11817
|
+
case "restore": {
|
|
11818
|
+
db = need2(db, t("database (id or name)", "la base (id o nombre)"), "ghosty dbs restore <agent-id> <db> <checkpoint-id> [--yes]");
|
|
11819
|
+
const ckpt = need2(rest[0], t("checkpoint id (from dbs checkpoints)", "el id del checkpoint (de dbs checkpoints)"), `ghosty dbs restore ${id} ${db} <checkpoint-id>`);
|
|
11820
|
+
await confirm(t(`Return every table of ${db} to checkpoint ${ckpt}? A new checkpoint is taken first, so you can undo it.`, `\xBFRegresar todas las tablas de ${db} al checkpoint ${ckpt}? Antes se toma otro, as\xED que se puede deshacer.`), { yes: v.yes, retry: `ghosty dbs restore ${id} ${db} ${ckpt}` });
|
|
11821
|
+
const r = await api(agentPath2(id, `/dbs/${enc8(db)}/checkpoints`), { method: "POST", body: { checkpointId: ckpt } });
|
|
11822
|
+
return out(r, () => `${lavender("\u2713")} ${t(`${r.db} returned to ${r.restoredTo.at}.`, `${r.db} regresada a ${r.restoredTo.at}.`)} ${dim(r.undo ? t(`Undo: ghosty dbs restore ${id} ${db} ${r.undo.id}`, `Para deshacer: ghosty dbs restore ${id} ${db} ${r.undo.id}`) : r.warning ?? "")}`);
|
|
11823
|
+
}
|
|
11722
11824
|
case "grant": {
|
|
11723
11825
|
db = need2(db, t("database (id or name)", "la base (id o nombre)"), "ghosty dbs grant <agent-id> <db> [--external-write t1,t2] [--external-rows t:col+col]");
|
|
11724
11826
|
let rowScope;
|
|
@@ -11881,6 +11983,7 @@ function skipReason(r) {
|
|
|
11881
11983
|
reaction: ["only a reaction", "s\xF3lo una reacci\xF3n"],
|
|
11882
11984
|
channel_off: ["WhatsApp channel off for this agent", "canal de WhatsApp apagado en este agente"],
|
|
11883
11985
|
no_quota: ["out of balance", "sin saldo"],
|
|
11986
|
+
own_number: ["sent by another of our agent numbers (bot loop guard)", "lo mand\xF3 otro n\xFAmero nuestro con agente (guarda de bucle)"],
|
|
11884
11987
|
partner_token: ["partner did not issue a turn token", "el partner no dio token de turno"],
|
|
11885
11988
|
partner_busy: ["partner at its concurrent-turn limit", "el partner lleg\xF3 a su tope de turnos a la vez"]
|
|
11886
11989
|
};
|
|
@@ -13238,6 +13341,35 @@ var HELPS_ES = {
|
|
|
13238
13341
|
summary: "Ghosty para Chrome: cerrar la sesi\xF3n del navegador.",
|
|
13239
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."]
|
|
13240
13343
|
},
|
|
13344
|
+
image: {
|
|
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.",
|
|
13346
|
+
replace: [
|
|
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"],
|
|
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"']
|
|
13353
|
+
],
|
|
13354
|
+
flags: [
|
|
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)"],
|
|
13363
|
+
["--tenant ID", "el negocio (externalId) para el que es: va al desglose de consumo y a su tope diario opcional"],
|
|
13364
|
+
["--agent SLUG", "a qu\xE9 agente del partner se carga en el desglose (default: el de siempre)"],
|
|
13365
|
+
["--out FILE", "adem\xE1s baja el PNG aqu\xED (varias: FILE-1.png, FILE-2.png\u2026)"]
|
|
13366
|
+
],
|
|
13367
|
+
notes: [
|
|
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}'.`,
|
|
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."
|
|
13371
|
+
]
|
|
13372
|
+
},
|
|
13241
13373
|
me: {
|
|
13242
13374
|
summary: "Tu cuenta: archivos, memorias, documentos editables y uso.",
|
|
13243
13375
|
replace: [
|
|
@@ -13494,6 +13626,7 @@ var HELPS_ES = {
|
|
|
13494
13626
|
["--currency C", "pin: usd (default) o mxn \u2014 la moneda del cobro si hay que pagar"],
|
|
13495
13627
|
["--add-pack", "pin: ya usas tus lugares \u2014 suma 3 m\xE1s (mismo periodo y moneda de tu suscripci\xF3n) y fija \xE9ste"],
|
|
13496
13628
|
["--cancel / --resume", "pins: cancela al final del periodo (los sitios vuelven a Gratis con aviso), o lo deshace"],
|
|
13629
|
+
["--days N", "search: la ventana de Search Console en d\xEDas (default 28; Google reporta con 2\u20133 d\xEDas de retraso)"],
|
|
13497
13630
|
["--title T", "publish: el nombre del sitio (default: el <title> del HTML o el nombre de la carpeta)"],
|
|
13498
13631
|
["--slug S", "publish: el slug de un sitio NUEVO (a-z, 0-9 y guiones, 3\u201360, no reservado)"],
|
|
13499
13632
|
["--site X", "publish: actualiza ese sitio de la casa (slug, id o URL) en vez de crear uno"]
|
|
@@ -13514,7 +13647,7 @@ var HELPS_ES = {
|
|
|
13514
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."]
|
|
13515
13648
|
},
|
|
13516
13649
|
spaces: {
|
|
13517
|
-
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.",
|
|
13518
13651
|
flags: [
|
|
13519
13652
|
["--user EMAIL", "ls (staff): los espacios de esa persona"],
|
|
13520
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)"],
|
|
@@ -13524,8 +13657,9 @@ var HELPS_ES = {
|
|
|
13524
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"],
|
|
13525
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"],
|
|
13526
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"],
|
|
13527
|
-
["--until DATE", "renew: el nuevo \xABpagado hasta\xBB (AAAA-MM-DD)"],
|
|
13528
|
-
["--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)"],
|
|
13529
13663
|
["--to EMAIL", "transfer: el due\xF1o nuevo (si no tiene cuenta se precrea y la reclama al entrar)"],
|
|
13530
13664
|
["--keep-as R", "transfer: el rol del due\xF1o anterior \u2014 admin | member (default) | none (sale del espacio)"],
|
|
13531
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"],
|
|
@@ -13533,7 +13667,7 @@ var HELPS_ES = {
|
|
|
13533
13667
|
["-n, --dry-run", "ense\xF1a qu\xE9 cambia, no cambia nada"],
|
|
13534
13668
|
["--yes", "s\xE1ltate la confirmaci\xF3n (obligatorio sin terminal)"]
|
|
13535
13669
|
],
|
|
13536
|
-
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."]
|
|
13537
13671
|
},
|
|
13538
13672
|
staff: {
|
|
13539
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.",
|
|
@@ -13589,7 +13723,7 @@ var HELPS_ES = {
|
|
|
13589
13723
|
["--note T", "changes: qu\xE9 cambiar del plan (o por qu\xE9 replanear tras un escalado). approve tras un escalado: qu\xE9 debe arreglar @build"],
|
|
13590
13724
|
["--check-scope T", "approve/changes: lo \xFAnico que @check revisa en la siguiente vuelta (lo propone runs advise); lo nuevo va como nota, no como hallazgo"],
|
|
13591
13725
|
["--skip-preview", "merge: mergea sin la preview que ped\xEDa el plan (queda en bit\xE1cora)"],
|
|
13592
|
-
["--gen
|
|
13726
|
+
["--gen KEY,KEY", "env push: genera ah\xED mismo llaves al azar (32 bytes hex) con esos nombres; nunca se imprimen"],
|
|
13593
13727
|
["--replace", "env push: reemplaza el .env entero de la preview (por defecto agrega y deja las dem\xE1s)"],
|
|
13594
13728
|
["--create", "rooms connect: crea el room si no existe"],
|
|
13595
13729
|
["--private", "rooms connect --create: el room nuevo es privado (s\xF3lo t\xFA, y a quien agregues)"],
|
|
@@ -13836,6 +13970,8 @@ var HELPS = {
|
|
|
13836
13970
|
"ghosty dbs tables <agent-id> <db>",
|
|
13837
13971
|
'ghosty dbs query <agent-id> <db> "SQL" [--arg V]\u2026 [--write]',
|
|
13838
13972
|
"ghosty dbs origin <agent-id> <db> [--table T] [--since 2026-10-10] [--limit N]",
|
|
13973
|
+
"ghosty dbs checkpoints <agent-id> <db>",
|
|
13974
|
+
"ghosty dbs restore <agent-id> <db> <checkpoint-id> [--yes]",
|
|
13839
13975
|
"ghosty dbs export <agent-id> <db> [--table T] [--out FILE]",
|
|
13840
13976
|
"ghosty dbs import <agent-id> <db> --from easybits:<db-id> [--tables a,b] [--append] [--rehost-images t.col,\u2026] [--dry-run] [--yes]",
|
|
13841
13977
|
"ghosty dbs rehost <agent-id> <db> --table T --column C [--dry-run]",
|
|
@@ -14020,6 +14156,37 @@ var HELPS = {
|
|
|
14020
14156
|
notes: ["Revokes every Ghosty for Chrome token your terminal agents hold (Claude Code, CLI, @ghostystudio/browser-mcp) and disconnects the extension. Copy a new command from the extension panel to reconnect."],
|
|
14021
14157
|
learn: `${REF}#navegador`
|
|
14022
14158
|
},
|
|
14159
|
+
image: {
|
|
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
|
+
],
|
|
14165
|
+
flags: [
|
|
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)"],
|
|
14174
|
+
["--tenant ID", "the business (externalId) it is for: it goes to the usage breakdown and to its optional daily cap"],
|
|
14175
|
+
["--agent SLUG", "which partner agent it is charged to in the breakdown (default: the main one)"],
|
|
14176
|
+
["--out FILE", "also download the PNG here (several: FILE-1.png, FILE-2.png\u2026)"]
|
|
14177
|
+
],
|
|
14178
|
+
examples: [
|
|
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',
|
|
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'
|
|
14182
|
+
],
|
|
14183
|
+
notes: [
|
|
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}'.`,
|
|
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."
|
|
14187
|
+
],
|
|
14188
|
+
learn: `${DOCS}/partners#imagenes-con-ia`
|
|
14189
|
+
},
|
|
14023
14190
|
me: {
|
|
14024
14191
|
summary: "Your account: files, memories, editable docs and usage.",
|
|
14025
14192
|
usage: [
|
|
@@ -14382,8 +14549,8 @@ HELPS.novedades = {
|
|
|
14382
14549
|
learn: `${REF}#soporte`
|
|
14383
14550
|
};
|
|
14384
14551
|
HELPS.spaces = {
|
|
14385
|
-
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.",
|
|
14386
|
-
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]"],
|
|
14387
14554
|
flags: [
|
|
14388
14555
|
["--user EMAIL", "ls (staff): that person's workspaces"],
|
|
14389
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)"],
|
|
@@ -14393,8 +14560,9 @@ HELPS.spaces = {
|
|
|
14393
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"],
|
|
14394
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"],
|
|
14395
14562
|
["--house-claude on|off", "set (staff): its agents run on Ghosty's Claude when the owner brings no key; recycles their Claude boxes"],
|
|
14396
|
-
["--until DATE", "renew: the new \xABpaid until\xBB (YYYY-MM-DD)"],
|
|
14397
|
-
["--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)"],
|
|
14398
14566
|
["--to EMAIL", "transfer: the new owner (if they have no account it is pre-created and claimed on login)"],
|
|
14399
14567
|
["--keep-as R", "transfer: the previous owner's role \u2014 admin | member (default) | none (removed)"],
|
|
14400
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"],
|
|
@@ -14402,8 +14570,8 @@ HELPS.spaces = {
|
|
|
14402
14570
|
["-n, --dry-run", "show what changes, change nothing"],
|
|
14403
14571
|
["--yes", "skip the confirmation (required without a terminal)"]
|
|
14404
14572
|
],
|
|
14405
|
-
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"],
|
|
14406
|
-
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."],
|
|
14407
14575
|
learn: `${REF}#espacios`
|
|
14408
14576
|
};
|
|
14409
14577
|
HELPS.workspaces = HELPS.spaces;
|
|
@@ -14425,6 +14593,7 @@ HELPS.sites = {
|
|
|
14425
14593
|
"ghosty sites pin <slug|id> [--interval year|month] [--currency usd|mxn] [--add-pack]",
|
|
14426
14594
|
"ghosty sites unpin <slug|id>",
|
|
14427
14595
|
"ghosty sites pins [--cancel | --resume]",
|
|
14596
|
+
"ghosty sites search <slug|id> [--days 28]",
|
|
14428
14597
|
"ghosty sites publish <file.html|folder> [--title T] [--slug S] [--site <slug|id>]",
|
|
14429
14598
|
"ghosty sites slug <slug|id> <new-slug>"
|
|
14430
14599
|
],
|
|
@@ -14434,6 +14603,7 @@ HELPS.sites = {
|
|
|
14434
14603
|
["--currency C", "pin: usd (default) or mxn \u2014 the currency charged if you need to pay"],
|
|
14435
14604
|
["--add-pack", "pin: you already use your slots \u2014 add 3 more (same period and currency as your subscription) and pin this one"],
|
|
14436
14605
|
["--cancel / --resume", "pins: cancel at period end (sites go back to Free with notice), or undo it"],
|
|
14606
|
+
["--days N", "search: Search Console window in days (default 28; Google reports 2\u20133 days late)"],
|
|
14437
14607
|
["--title T", "publish: the site's name (default: the HTML <title> or the folder name)"],
|
|
14438
14608
|
["--slug S", "publish: the slug for a NEW site (a-z, 0-9 and hyphens, 3\u201360, not reserved)"],
|
|
14439
14609
|
["--site X", "publish: update that house site (slug, id or URL) instead of creating one"]
|
|
@@ -14585,7 +14755,7 @@ function helpText(cmd) {
|
|
|
14585
14755
|
|
|
14586
14756
|
// src/update.ts
|
|
14587
14757
|
init_i18n();
|
|
14588
|
-
import { mkdir as mkdir5, readFile as readFile9, writeFile as
|
|
14758
|
+
import { mkdir as mkdir5, readFile as readFile9, writeFile as writeFile9 } from "node:fs/promises";
|
|
14589
14759
|
import { homedir as homedir3 } from "node:os";
|
|
14590
14760
|
import { dirname as dirname3, join as join7 } from "node:path";
|
|
14591
14761
|
var FILE = join7(process.env.XDG_CONFIG_HOME || join7(homedir3(), ".config"), "ghosty", "update.json");
|
|
@@ -14611,7 +14781,7 @@ async function latestVersion(current2) {
|
|
|
14611
14781
|
const latest = (await r.json()).version;
|
|
14612
14782
|
if (latest) cache2 = { latest, checkedAt: Date.now() };
|
|
14613
14783
|
await mkdir5(dirname3(FILE), { recursive: true });
|
|
14614
|
-
await
|
|
14784
|
+
await writeFile9(FILE, JSON.stringify(cache2));
|
|
14615
14785
|
} catch {
|
|
14616
14786
|
}
|
|
14617
14787
|
}
|
|
@@ -14691,7 +14861,7 @@ function agentArgIndex(pos) {
|
|
|
14691
14861
|
}
|
|
14692
14862
|
|
|
14693
14863
|
// src/completion.ts
|
|
14694
|
-
import { mkdir as mkdir6, readFile as readFile10, writeFile as
|
|
14864
|
+
import { mkdir as mkdir6, readFile as readFile10, writeFile as writeFile10 } from "node:fs/promises";
|
|
14695
14865
|
import { homedir as homedir4 } from "node:os";
|
|
14696
14866
|
import { join as join8 } from "node:path";
|
|
14697
14867
|
var GLOBAL_FLAGS = ["--json", "--token", "--profile", "--yes", "--help", "--version", "--lang", "--dry-run"];
|
|
@@ -14743,7 +14913,7 @@ async function names() {
|
|
|
14743
14913
|
const workspaces = [...new Set(list2.map((a) => a.espacio?.tipo === "workspace" ? a.espacio.nombre : void 0).filter((x) => !!x))];
|
|
14744
14914
|
await mkdir6(join8(cacheFile(), ".."), { recursive: true }).catch(() => {
|
|
14745
14915
|
});
|
|
14746
|
-
await
|
|
14916
|
+
await writeFile10(cacheFile(), JSON.stringify({ at: Date.now(), agents, workspaces })).catch(() => {
|
|
14747
14917
|
});
|
|
14748
14918
|
return { agents, workspaces };
|
|
14749
14919
|
}
|
|
@@ -14830,7 +15000,7 @@ init_i18n();
|
|
|
14830
15000
|
// src/commands/spec.ts
|
|
14831
15001
|
var import_yaml = __toESM(require_dist(), 1);
|
|
14832
15002
|
init_api();
|
|
14833
|
-
import { mkdir as mkdir7, readdir as readdir4, readFile as readFile11, stat as stat2, writeFile as
|
|
15003
|
+
import { mkdir as mkdir7, readdir as readdir4, readFile as readFile11, stat as stat2, writeFile as writeFile11 } from "node:fs/promises";
|
|
14834
15004
|
import { join as join9, resolve as resolve2 } from "node:path";
|
|
14835
15005
|
init_util();
|
|
14836
15006
|
init_i18n();
|
|
@@ -14844,7 +15014,7 @@ async function agentsExport(id, v) {
|
|
|
14844
15014
|
}
|
|
14845
15015
|
const dir = resolve2(v.out);
|
|
14846
15016
|
await mkdir7(dir, { recursive: true });
|
|
14847
|
-
await
|
|
15017
|
+
await writeFile11(join9(dir, "agent.yaml"), yaml);
|
|
14848
15018
|
const own = (0, import_yaml.parse)(yaml)["x-ghosty"]?.skills?.own ?? [];
|
|
14849
15019
|
for (const slug of own) {
|
|
14850
15020
|
const sk = await api(`/api/v2/agents/${enc12(id)}/skills/${enc12(slug)}`);
|
|
@@ -14967,7 +15137,7 @@ ${dim(t(`${r.totals.activeTurns} turn(s) running`, `${r.totals.activeTurns} turn
|
|
|
14967
15137
|
init_api();
|
|
14968
15138
|
init_auth();
|
|
14969
15139
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
14970
|
-
import { mkdir as mkdir8, readFile as readFile12, writeFile as
|
|
15140
|
+
import { mkdir as mkdir8, readFile as readFile12, writeFile as writeFile12 } from "node:fs/promises";
|
|
14971
15141
|
import { homedir as homedir5 } from "node:os";
|
|
14972
15142
|
import { dirname as dirname4, join as join10 } from "node:path";
|
|
14973
15143
|
init_i18n();
|
|
@@ -15012,7 +15182,7 @@ async function visitorCookie(base, slug, fresh) {
|
|
|
15012
15182
|
if (!cookie) throw new CliError(t("The demo didn't hand out a visitor cookie.", "El demo no entreg\xF3 cookie de visitante."), EXIT.API);
|
|
15013
15183
|
jar[slug] = cookie;
|
|
15014
15184
|
await mkdir8(dirname4(jarPath()), { recursive: true });
|
|
15015
|
-
await
|
|
15185
|
+
await writeFile12(jarPath(), JSON.stringify(jar, null, 2), { mode: 384 });
|
|
15016
15186
|
return cookie;
|
|
15017
15187
|
}
|
|
15018
15188
|
async function visitorTurn(base, slug, cookie, text) {
|
|
@@ -15127,8 +15297,8 @@ var PACK = { year: { usd: 49, mxn: 990 }, month: { usd: 5, mxn: 99 } };
|
|
|
15127
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"}`;
|
|
15128
15298
|
var kb = (n) => n ? `${Math.max(1, Math.round(n / 1024))} KB` : "";
|
|
15129
15299
|
var day = (iso) => iso ? iso.slice(0, 10) : "";
|
|
15130
|
-
async function sitesCmd(sub, a1, a2, v) {
|
|
15131
|
-
const ex = "ghosty sites ls [--house] \xB7 pin|unpin <slug|id> \xB7 pins [--cancel|--resume] \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>";
|
|
15132
15302
|
switch (sub ?? "ls") {
|
|
15133
15303
|
case "ls":
|
|
15134
15304
|
case "list": {
|
|
@@ -15169,6 +15339,25 @@ ${dim(r.expiresAt ? t(`Free rule: pauses ${day(r.expiresAt)} unless it changes (
|
|
|
15169
15339
|
${table(r.pinned.map((p) => ({ slug: p.slug, title: (p.title ?? "").slice(0, 40), url: p.url, since: day(p.pinnedAt) })), ["slug", "title", "url", "since"])}` : t("No pinned sites. Pin one ($49 USD/yr or $5 USD/mo, includes up to 3 sites): ghosty sites pin <slug>", "Sin sitios fijos. Fija uno ($49 USD al a\xF1o o $5 USD al mes, incluye hasta 3 sitios): ghosty sites pin <slug>")
|
|
15170
15340
|
);
|
|
15171
15341
|
}
|
|
15342
|
+
case "search": {
|
|
15343
|
+
if (!a1) throw usage(t("Missing the site (slug, id or URL).", "Falta el sitio (slug, id o URL)."), "ghosty sites search <slug|id> [--days 28]");
|
|
15344
|
+
const r = await api(`/api/v2/sites/${encodeURIComponent(a1)}/search${v.days ? `?days=${encodeURIComponent(v.days)}` : ""}`);
|
|
15345
|
+
const p = r.portada;
|
|
15346
|
+
const index = p.error ? dim(p.error) : p.indexada ? `${lavender("\u2713")} ${t("indexed", "indexada")} ${dim(day(p.ultimoRastreo ?? null))}` : `${t("not indexed", "sin indexar")} ${dim(p.estado ?? "")}`;
|
|
15347
|
+
const tot = r.total;
|
|
15348
|
+
return out(
|
|
15349
|
+
r,
|
|
15350
|
+
() => [
|
|
15351
|
+
`${bold(r.sitio)} ${dim(`${r.desde} \u2192 ${r.hasta}`)}`,
|
|
15352
|
+
`${t("Home", "Portada")}: ${index}`,
|
|
15353
|
+
`${t("clicks", "clics")} ${tot.clics} \xB7 ${t("impressions", "impresiones")} ${tot.impresiones} \xB7 CTR ${tot.ctr} \xB7 ${t("position", "posici\xF3n")} ${tot.posicion ?? "\u2014"}`,
|
|
15354
|
+
r.busquedas.length ? table(r.busquedas.map((q) => ({ query: q.busqueda, clicks: q.clics, impressions: q.impresiones, position: q.posicion })), ["query", "clicks", "impressions", "position"]) : dim(t("No searches yet (Google reports 2\u20133 days late).", "A\xFAn sin b\xFAsquedas (Google reporta con 2\u20133 d\xEDas de atraso)."))
|
|
15355
|
+
].join("\n")
|
|
15356
|
+
);
|
|
15357
|
+
}
|
|
15358
|
+
case "domain":
|
|
15359
|
+
case "domains":
|
|
15360
|
+
return domainCmd(a1, a2, a3);
|
|
15172
15361
|
case "publish":
|
|
15173
15362
|
case "deploy": {
|
|
15174
15363
|
if (!a1) throw usage(t("Missing the file or folder.", "Falta el archivo o la carpeta."), ex);
|
|
@@ -15195,10 +15384,45 @@ ${dim(t("Links with the old slug may stop working.", "Las ligas con el slug viej
|
|
|
15195
15384
|
throw usage(t(`Unknown sites subcommand: ${sub}.`, `Subcomando de sites desconocido: ${sub}.`), ex);
|
|
15196
15385
|
}
|
|
15197
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
|
+
}
|
|
15198
15422
|
|
|
15199
15423
|
// src/commands/docs.ts
|
|
15200
15424
|
init_api();
|
|
15201
|
-
import { writeFile as
|
|
15425
|
+
import { writeFile as writeFile13 } from "node:fs/promises";
|
|
15202
15426
|
|
|
15203
15427
|
// ../docs/src/core/doc-blocks.ts
|
|
15204
15428
|
var DOC_ENVELOPE_VERSION = 1;
|
|
@@ -15361,7 +15585,7 @@ ${t("Ids: ghosty me docs ls", "Ids: ghosty me docs ls")}`);
|
|
|
15361
15585
|
}
|
|
15362
15586
|
const named = /filename\*=UTF-8''([^;]+)/i.exec(res.headers.get("content-disposition") ?? "")?.[1];
|
|
15363
15587
|
const file = v.out ?? (named ? decodeURIComponent(named) : fileName(id, format));
|
|
15364
|
-
await
|
|
15588
|
+
await writeFile13(file, bytes);
|
|
15365
15589
|
return out({ id, format, saved: file, bytes: bytes.length }, () => `${lavender("\u2713")} ${file} (${bytes.length} bytes)`);
|
|
15366
15590
|
}
|
|
15367
15591
|
case "check": {
|
|
@@ -15387,7 +15611,7 @@ ${t("Ids: ghosty me docs ls", "Ids: ghosty me docs ls")}`);
|
|
|
15387
15611
|
if (res.status === 204) return out({ id, block, segment, segments, saved: null }, () => dim(t("That block has no text to read.", "Ese bloque no tiene texto que leer.")));
|
|
15388
15612
|
const bytes = Buffer.from(await res.arrayBuffer());
|
|
15389
15613
|
const file = v.out ?? `${id}-${block}${segment !== null ? `-${segment}` : ""}.${audioExt(res.headers.get("content-type"))}`;
|
|
15390
|
-
await
|
|
15614
|
+
await writeFile13(file, bytes);
|
|
15391
15615
|
return out({ id, block, segment, segments, saved: file, bytes: bytes.length }, () => `${lavender("\u2713")} ${file} (${bytes.length} bytes) ${dim(t(`\xB7 the block has ${segments} sentence(s): --segment 0\u2026${Math.max(segments - 1, 0)}`, `\xB7 el bloque tiene ${segments} frase(s): --segment 0\u2026${Math.max(segments - 1, 0)}`))}`);
|
|
15392
15616
|
}
|
|
15393
15617
|
case "restore": {
|
|
@@ -15901,20 +16125,25 @@ ${dim(`${t("Detail", "Detalle")}: ghosty factory runs show <run> --workspace ${r
|
|
|
15901
16125
|
const { advice: a, workspace } = await api(`${path}/advise`, { body: {} });
|
|
15902
16126
|
const note = a.buildNote.map((p, i) => `${i + 1}. ${p.point}`).join(" ");
|
|
15903
16127
|
const sh = (x) => `'${x.replace(/'/g, `'\\''`)}'`;
|
|
15904
|
-
const apply = a.decision === "fix" ? `ghosty factory runs approve ${id} --note ${sh(note)}${a.checkScope ? ` --check-scope ${sh(a.checkScope)}` : ""} --workspace ${workspace}` : `ghosty factory runs changes ${id} --note ${sh(note)} --workspace ${workspace}
|
|
16128
|
+
const apply = a.decision === "fix" ? `ghosty factory runs approve ${id} --note ${sh(note)}${a.checkScope ? ` --check-scope ${sh(a.checkScope)}` : ""} --workspace ${workspace}` : a.decision === "replan" ? `ghosty factory runs changes ${id} --note ${sh(note)} --workspace ${workspace}` : a.decision === "recheck" ? `ghosty factory runs recheck ${id} --workspace ${workspace}` : null;
|
|
16129
|
+
const label = {
|
|
16130
|
+
fix: t("Let @build fix it", "Que @build lo arregle"),
|
|
16131
|
+
replan: t("Redo the plan", "Rehacer el plan"),
|
|
16132
|
+
close: t("Close the PR", "Cerrar el PR"),
|
|
16133
|
+
close_ignore: t("Close the PR and ignore this version", "Cerrar el PR e ignorar esta versi\xF3n"),
|
|
16134
|
+
recheck: t("Let @check review again", "Que @check revise otra vez"),
|
|
16135
|
+
wait: t("Wait: it's a platform fault", "Esperar: es una falla de la plataforma")
|
|
16136
|
+
}[a.decision] ?? a.decision;
|
|
15905
16137
|
return out({ workspace, advice: a, apply }, () => {
|
|
15906
16138
|
const conf = { high: t("high", "alta"), medium: t("medium", "media"), low: t("low", "baja") }[a.confidence] ?? a.confidence;
|
|
15907
16139
|
return [
|
|
15908
|
-
`${bold(`#${id}`)} ${bold(
|
|
16140
|
+
`${bold(`#${id}`)} ${bold(label)} ${dim(`\xB7 ${t("confidence", "confianza")} ${conf} \xB7 ${a.model}`)}`,
|
|
15909
16141
|
a.why,
|
|
15910
|
-
"",
|
|
15911
|
-
|
|
15912
|
-
...a.buildNote.map((p, i) => ` ${i + 1}. ${p.point}
|
|
15913
|
-
${dim(p.cites)}`),
|
|
16142
|
+
...a.buildNote.length ? ["", bold(a.decision === "fix" ? t("Note for @build", "Nota para @build") : t("What to change in the plan", "Qu\xE9 cambiar en el plan")), ...a.buildNote.map((p, i) => ` ${i + 1}. ${p.point}
|
|
16143
|
+
${dim(p.cites)}`)] : [],
|
|
15914
16144
|
...a.checkScope && a.decision === "fix" ? ["", bold(t("@check reviews only", "@check revisa s\xF3lo")), ` ${a.checkScope}`] : [],
|
|
15915
16145
|
"",
|
|
15916
|
-
dim(t("Nothing was applied. To apply it (edit the note first if you want):", "No se aplic\xF3 nada. Para aplicarla (edita la nota antes si quieres):")),
|
|
15917
|
-
` ${apply}`
|
|
16146
|
+
...apply ? [dim(t("Nothing was applied. To apply it (edit the note first if you want):", "No se aplic\xF3 nada. Para aplicarla (edita la nota antes si quieres):")), ` ${apply}`] : [dim(t("Nothing was applied. Decide it on the run's card or in the app.", "No se aplic\xF3 nada. Dec\xEDdelo en la tarjeta del pedido o en la app."))]
|
|
15918
16147
|
].join("\n");
|
|
15919
16148
|
});
|
|
15920
16149
|
}
|
|
@@ -16043,6 +16272,58 @@ async function settingsCmd(sub, key, value) {
|
|
|
16043
16272
|
throw usage(t(`Unknown settings subcommand: ${sub}.`, `Subcomando de settings desconocido: ${sub}.`), "ghosty settings ls|set|unset <KEY> [value]");
|
|
16044
16273
|
}
|
|
16045
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
|
+
|
|
16046
16327
|
// src/commands/ads.ts
|
|
16047
16328
|
init_api();
|
|
16048
16329
|
init_i18n();
|
|
@@ -16058,6 +16339,9 @@ async function adsCmd(sub, action, v) {
|
|
|
16058
16339
|
lavender(t("Meta ad accounts", "Cuentas de Meta")),
|
|
16059
16340
|
r.accounts.length ? table(r.accounts.map((a) => ({ workspace: a.workspace, account: a.account ?? "", active: `${a.active}/${a.campaigns}`, status: a.accountStatus ?? "", token: day3(a.tokenExpiresAt), checked: day3(a.checkedAt), alerted: day3(a.alertedAt), error: a.error ?? "" })), ["workspace", "account", "active", "status", "token", "checked", "alerted", "error"]) : dim(t("(none connected)", "(ninguna conectada)")),
|
|
16060
16341
|
"",
|
|
16342
|
+
lavender(t("Google Ads accounts", "Cuentas de Google Ads")),
|
|
16343
|
+
r.google?.length ? table(r.google.map((g) => ({ workspace: g.workspace, account: g.account, link: g.link, active: `${g.active}/${g.campaigns}`, status: g.accountStatus ?? "", checked: day3(g.checkedAt), alerted: day3(g.alertedAt), error: g.error ?? "" })), ["workspace", "account", "link", "active", "status", "checked", "alerted", "error"]) : dim(t("(none linked)", "(ninguna vinculada)")),
|
|
16344
|
+
"",
|
|
16061
16345
|
lavender(t("Ads-only WhatsApp numbers", "N\xFAmeros de WhatsApp \xABs\xF3lo anuncios\xBB")),
|
|
16062
16346
|
r.numbers.length ? table(r.numbers.map((n) => ({ number: n.number, "last ad lead": day3(n.lastAdLeadAt), alerted: day3(n.alertedAt) })), ["number", "last ad lead", "alerted"]) : dim(t("(none)", "(ninguno)"))
|
|
16063
16347
|
].join("\n")
|
|
@@ -16373,6 +16657,7 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
16373
16657
|
spaces join|leave <workspace> Enter or leave a client's workspace as staff (no seat; logged)
|
|
16374
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]
|
|
16375
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]
|
|
16376
16661
|
spaces rename <old> <new> Change its slug only [--dry-run]
|
|
16377
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]
|
|
16378
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]
|
|
@@ -16382,6 +16667,8 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
16382
16667
|
staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
|
|
16383
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]
|
|
16384
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)
|
|
16385
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]
|
|
16386
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]
|
|
16387
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]
|
|
@@ -16484,6 +16771,8 @@ ${bold("Sites")} ${dim("(sites your agents publish at <slug>.ghosty.page)")}
|
|
|
16484
16771
|
sites ls Sites your agents published (live and paused) [--house: Ghosty's own demos and landings (staff)]
|
|
16485
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]
|
|
16486
16773
|
sites unpin <slug|id> Release its slot (back to the Free rule: 30 days + notice)
|
|
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]
|
|
16487
16776
|
sites pins Your pinned-sites subscription and slots [--cancel | --resume]
|
|
16488
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]
|
|
16489
16778
|
sites slug <slug|id> <new-slug> Change a site's slug (staff)
|
|
@@ -16526,6 +16815,8 @@ ${bold("Browser")} ${dim("(Ghosty for Chrome)")}
|
|
|
16526
16815
|
|
|
16527
16816
|
${bold("Partners")} ${dim("(give an agent to each of YOUR customers \u2014 see: ghosty partner --help)")}
|
|
16528
16817
|
partner ls | enable | credentials | agent | tenants | audit | try
|
|
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]
|
|
16529
16820
|
|
|
16530
16821
|
${bold("Your account")}
|
|
16531
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]
|
|
@@ -16574,6 +16865,7 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
16574
16865
|
spaces join|leave <espacio> Entra o sal del espacio de un cliente como staff (sin asiento; queda en bit\xE1cora)
|
|
16575
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]
|
|
16576
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]
|
|
16577
16869
|
spaces rename <viejo> <nuevo> Cambia s\xF3lo su slug [--dry-run]
|
|
16578
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]
|
|
16579
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]
|
|
@@ -16583,6 +16875,8 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
16583
16875
|
staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
|
|
16584
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]
|
|
16585
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)
|
|
16586
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]
|
|
16587
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]
|
|
16588
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]
|
|
@@ -16686,6 +16980,7 @@ ${bold("Sitios")} ${dim("(los sitios que publican tus agentes en <slug>.ghosty.
|
|
|
16686
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]
|
|
16687
16981
|
sites unpin <slug|id> Suelta su lugar (vuelve a la regla Gratis: 30 d\xEDas + aviso)
|
|
16688
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]
|
|
16689
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]
|
|
16690
16985
|
sites slug <slug|id> <slug-nuevo> Cambia el slug de un sitio (staff)
|
|
16691
16986
|
|
|
@@ -16727,6 +17022,8 @@ ${bold("Navegador")} ${dim("(Ghosty para Chrome)")}
|
|
|
16727
17022
|
|
|
16728
17023
|
${bold("Partners")} ${dim("(dale un agente a cada uno de TUS clientes \u2014 ver: ghosty partner --help)")}
|
|
16729
17024
|
partner ls | enable | credentials | agent | tenants | audit | try
|
|
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]
|
|
16730
17027
|
|
|
16731
17028
|
${bold("Tu cuenta")}
|
|
16732
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]
|
|
@@ -16752,7 +17049,7 @@ ${bold("Opciones globales")}
|
|
|
16752
17049
|
${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorrecto \xB7 3 sin sesi\xF3n
|
|
16753
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.")}
|
|
16754
17051
|
${dim("Documentaci\xF3n: https://www.ghosty.studio/docs/cli")}`;
|
|
16755
|
-
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", "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"];
|
|
16756
17053
|
var AGENTS_SUBS = ["ls", "create", "get", "show", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "embed", "box", "token", "memory", "transfer"];
|
|
16757
17054
|
function unknown(what, input, known, helpCmd) {
|
|
16758
17055
|
const s2 = suggest(input, known);
|
|
@@ -16818,6 +17115,8 @@ async function main() {
|
|
|
16818
17115
|
in: { type: "string" },
|
|
16819
17116
|
every: { type: "string" },
|
|
16820
17117
|
until: { type: "string" },
|
|
17118
|
+
credit: { type: "string" },
|
|
17119
|
+
eligibility: { type: "string" },
|
|
16821
17120
|
title: { type: "string" },
|
|
16822
17121
|
body: { type: "string" },
|
|
16823
17122
|
profile: { type: "string" },
|
|
@@ -16896,6 +17195,7 @@ async function main() {
|
|
|
16896
17195
|
like: { type: "string" },
|
|
16897
17196
|
"copy-dbs": { type: "boolean" },
|
|
16898
17197
|
"copy-keys": { type: "boolean" },
|
|
17198
|
+
courtesy: { type: "boolean" },
|
|
16899
17199
|
"keep-as": { type: "string" },
|
|
16900
17200
|
"no-notify": { type: "boolean" },
|
|
16901
17201
|
board: { type: "string" },
|
|
@@ -17021,6 +17321,13 @@ async function main() {
|
|
|
17021
17321
|
draft: { type: "boolean" },
|
|
17022
17322
|
"ads-only": { type: "string" },
|
|
17023
17323
|
"partner-tenant": { type: "string" },
|
|
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" },
|
|
17330
|
+
aspect: { type: "string" },
|
|
17024
17331
|
tenant: { type: "string" },
|
|
17025
17332
|
"app-id": { type: "string" },
|
|
17026
17333
|
secret: { type: "string" },
|
|
@@ -17055,14 +17362,14 @@ async function main() {
|
|
|
17055
17362
|
const tokens = splitTokens(pos, v);
|
|
17056
17363
|
globals.token = tokens.session;
|
|
17057
17364
|
globals.profile = v.profile;
|
|
17058
|
-
if (v.version) return out({ version: "0.
|
|
17365
|
+
if (v.version) return out({ version: "0.83.0" }, () => "0.83.0");
|
|
17059
17366
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
17060
17367
|
const context = (await readConfig()).workspace;
|
|
17061
17368
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
17062
17369
|
const at = agentArgIndex(pos);
|
|
17063
17370
|
if (at !== null && pos[at]) pos[at] = await resolveAgent(pos[at], context);
|
|
17064
17371
|
for (const f of ["like", "prompt-base", "agent"]) {
|
|
17065
|
-
if (f === "agent" && pos[0] === "partner") continue;
|
|
17372
|
+
if (f === "agent" && (pos[0] === "partner" || pos[0] === "image")) continue;
|
|
17066
17373
|
const val = v[f];
|
|
17067
17374
|
if (typeof val === "string" && val !== "none") v[f] = await resolveAgent(val, context);
|
|
17068
17375
|
}
|
|
@@ -17158,7 +17465,7 @@ async function main() {
|
|
|
17158
17465
|
return novedadesCmd(sub, a1, v);
|
|
17159
17466
|
case "sites":
|
|
17160
17467
|
case "site":
|
|
17161
|
-
return sitesCmd(sub, a1, a2, v);
|
|
17468
|
+
return sitesCmd(sub, a1, a2, v, pos[4]);
|
|
17162
17469
|
case "board":
|
|
17163
17470
|
return boardCmd(sub, a1, v, a2);
|
|
17164
17471
|
case "boards":
|
|
@@ -17196,6 +17503,8 @@ async function main() {
|
|
|
17196
17503
|
return browserCmd(sub, v);
|
|
17197
17504
|
case "partner":
|
|
17198
17505
|
return partnerCmd(sub, a1, a2, { ...v, token: tokens.turn }, pos[4]);
|
|
17506
|
+
case "image":
|
|
17507
|
+
return imageCmd(sub, a1, a2, v);
|
|
17199
17508
|
case "usage":
|
|
17200
17509
|
if (v.images) return imageUsage(v);
|
|
17201
17510
|
if (v.boxes && v.by === "template") return fleetBoxes();
|
|
@@ -17222,6 +17531,8 @@ async function main() {
|
|
|
17222
17531
|
return staffCmd(sub, a1, a2, v);
|
|
17223
17532
|
case "settings":
|
|
17224
17533
|
return settingsCmd(sub, a1, a2);
|
|
17534
|
+
case "coupons":
|
|
17535
|
+
return couponsCmd(sub, a1, v);
|
|
17225
17536
|
case "ads":
|
|
17226
17537
|
return adsCmd(sub, a1, v);
|
|
17227
17538
|
case "audit":
|
|
@@ -17250,7 +17561,7 @@ async function main() {
|
|
|
17250
17561
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
17251
17562
|
}
|
|
17252
17563
|
}
|
|
17253
|
-
var notice = updateNotice("0.
|
|
17564
|
+
var notice = updateNotice("0.83.0").catch(() => null);
|
|
17254
17565
|
main().then(
|
|
17255
17566
|
async () => {
|
|
17256
17567
|
const n = await notice;
|
package/package.json
CHANGED