@ghostystudio/cli 0.92.0 → 0.93.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/index.js +141 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -153,6 +153,14 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
|
|
|
153
153
|
|
|
154
154
|
Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
155
155
|
|
|
156
|
+
### Changes in 0.93.1
|
|
157
|
+
|
|
158
|
+
- `factory runs choose` also offers `fix_main`: a separate run fixes the main branch (CI permission, workflow) and the escalated run waits for it — it no longer counts as «your turn» — then updates itself and goes back to @check when the fix merges.
|
|
159
|
+
|
|
160
|
+
### Changes in 0.93.0
|
|
161
|
+
|
|
162
|
+
- `factory runs choose <run> [a|b|c]`: when @check escalates a decision it leaves 2–3 concrete paths (build, recheck, replan, close, merge_as_is). Without a letter it lists them; with one it applies it and the choice reaches the next role word for word. `merge_as_is` merges with CI as it is (red checks the PR didn't cause), asks for confirmation and is logged. `runs show` lists the options of an escalated run.
|
|
163
|
+
|
|
156
164
|
### Changes in 0.88.0
|
|
157
165
|
|
|
158
166
|
- `me files rm` takes several ids (`a,b` or `a b`) and `--q TEXT`, lists what it will delete, asks first (without a terminal it needs `--yes`; before, it deleted without asking) and `--dry-run` only shows the list.
|
package/dist/index.js
CHANGED
|
@@ -1175,7 +1175,7 @@ async function postLong(path2, body, timeoutMs = 9e5) {
|
|
|
1175
1175
|
const req = httpsRequest(`${base}${path2}`, {
|
|
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.93.1"}`, "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(path2, 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.93.1"}`,
|
|
1221
1221
|
"accept-language": lang(),
|
|
1222
1222
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
1223
1223
|
...opts.headers
|
|
@@ -11278,7 +11278,7 @@ async function call(path2, v, init = {}) {
|
|
|
11278
11278
|
"x-ghosty-ts": ts,
|
|
11279
11279
|
"x-ghosty-sig": sig,
|
|
11280
11280
|
"content-type": "application/json",
|
|
11281
|
-
"user-agent": `ghosty-cli/${"0.
|
|
11281
|
+
"user-agent": `ghosty-cli/${"0.93.1"}`
|
|
11282
11282
|
},
|
|
11283
11283
|
body: method === "GET" ? void 0 : raw
|
|
11284
11284
|
});
|
|
@@ -14028,7 +14028,8 @@ var HELPS_ES = {
|
|
|
14028
14028
|
"--timing lee la transcripci\xF3n de cada rol: los motores sin una (ACP) salen con minutos y costo, pero sin comandos. Tambi\xE9n lista los atascos: un comando abierto 8+ min, el mismo comando 4 veces, el mismo error 3 veces, ir y venir entre dos acciones, o apt install dentro de una caja.",
|
|
14029
14029
|
"advise: con un pedido ESCALADO, qu\xE9 hacer \u2014que @build lo arregle o rehacer el plan\u2014 con la nota para @build punto por punto (cada uno cita el hallazgo o el paso del plan que lo justifica) y qu\xE9 debe revisar @check. Compara los hallazgos de @check contra el plan firmado. No aplica nada: imprime el comando exacto de approve/changes. show dice por qu\xE9 se escal\xF3.",
|
|
14030
14030
|
"why: si el pedido no fue sano (atascos, @build de m\xE1s de 30 min, vueltas, CI rojo, escalado), una categor\xEDa (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), el paso cr\xEDtico con su evidencia y qu\xE9 cambiar la pr\xF3xima vez. Primero cruza los criterios del plan aprobado con la evidencia: aprobado sin la preview que ped\xEDa un criterio, mezclado sin preview, smoke rojo sobre el commit mezclado o criterio de CI con CI none \u2192 approved_unmet_criterion, arriba de cualquier atasco. Un pedido sano no llama al modelo. Cuando un pedido cierra sin ser sano, el room recibe este resumen en su hilo.",
|
|
14031
|
-
"Mientras un rol trabaja, si se atora el room recibe un \u23F3 en el hilo y al rol se le dice qu\xE9 revisar; desde la segunda vez en el mismo pedido, quien lo pidi\xF3 recibe un push."
|
|
14031
|
+
"Mientras un rol trabaja, si se atora el room recibe un \u23F3 en el hilo y al rol se le dice qu\xE9 revisar; desde la segunda vez en el mismo pedido, quien lo pidi\xF3 recibe un push.",
|
|
14032
|
+
"choose: cuando @check escala una decisi\xF3n deja 2\u20133 caminos concretos (a, b, c), cada uno con su acci\xF3n: build (@build lo hace en la rama), recheck, replan, close, merge_as_is o fix_main (abre un pedido aparte que arregla la rama principal; \xE9ste espera sin contar como \xABte toca\xBB y, al mergearse el arreglo, se pone al d\xEDa y se revisa solo). Sin letra los lista; con letra lo aplica y la elecci\xF3n le llega literal al siguiente rol. merge_as_is hace merge con el CI como est\xE1 (con checks en rojo): \xFAsalo cuando lo rojo no lo causa el PR; pide confirmaci\xF3n y queda en bit\xE1cora (merge_override). show tambi\xE9n lista las opciones."
|
|
14032
14033
|
]
|
|
14033
14034
|
}
|
|
14034
14035
|
};
|
|
@@ -15002,6 +15003,7 @@ HELPS.factory = {
|
|
|
15002
15003
|
"ghosty factory env ls [OWNER/REPO] [--workspace SLUG]",
|
|
15003
15004
|
"ghosty factory env push [OWNER/REPO] [FILE] [--gen KEY,KEY] [--replace] [--yes] [--workspace SLUG]",
|
|
15004
15005
|
"ghosty factory runs recheck <run> [--yes] [--workspace SLUG]",
|
|
15006
|
+
"ghosty factory runs choose <run> [a|b|c] [--yes] [--workspace SLUG]",
|
|
15005
15007
|
`ghosty factory run "What, why and how we know it's done" --repo OWNER/REPO [--room R] [--wait] [--timeout 1800] [--workspace SLUG]`,
|
|
15006
15008
|
"ghosty factory runs watch <run> | --thread <id> [--timeout 1800] [--workspace SLUG]",
|
|
15007
15009
|
'ghosty factory runs approve <run> --plan-version N [--note "\u2026"] [--check-scope "\u2026"] [--yes]',
|
|
@@ -15041,7 +15043,7 @@ HELPS.factory = {
|
|
|
15041
15043
|
["--yes", "rename, approve, changes, merge: skip the confirmation (required without a terminal)"]
|
|
15042
15044
|
],
|
|
15043
15045
|
examples: ["ghosty factory rooms connect blissito/ghosty-studio --room studio --create --workspace business", 'ghosty factory run "Add a COLLABORATOR role: invited by room, lands in the room, no personal agent. Done when an invite to #factory logs in straight there" --repo blissito/ghosty-studio --wait --workspace business', "ghosty factory runs approve 31 --plan-version 2 --workspace business", "ghosty factory runs watch 31 --workspace business", "ghosty factory runs merge 31 --workspace business", "ghosty factory runs ls --workspace business --room mailmask", "ghosty factory runs show 15 --workspace business", "ghosty factory runs show 13 --timing --workspace mercadito-verde", "ghosty factory runs why 13 --workspace mercadito-verde", "ghosty factory runs advise 115 --workspace business", "ghosty factory runs stats --since 7d --workspace mercadito-verde", 'ghosty factory runs rename 15 "Docs del CLI al d\xEDa" --workspace business --dry-run'],
|
|
15044
|
-
notes: ["env: the preview's environment variables live on your computer, so your terminal agent pushes them. ls lists saved and missing names (from .env.example and from runs escalated because the preview won't start); push adds them (only the workspace owner). Use disposable values, never production: the preview runs the repo's code. Values never come back. Then runs recheck <run>: @check reviews the same PR again without another @build loop. Logged as factory.env_set and factory.run_recheck.", "sprints: when the goal is too big for one run, @plan proposes a sprint (3\u20138 tickets in order, with dependencies) as a draft. approve signs every included ticket at once; they start one at a time as their dependencies merge. Only the owner or whoever asked can approve. Logged as factory.sprint_approve.", "rooms repos lists the repos your GitHub App sees (most recent first) and which rooms each one is already in.", "rooms connect checks that YOUR GitHub App installation sees the repo (if not, it gives you the link to grant access) and tells you how ready the repo is for agents (levels 1\u20133 and what's missing). Any member can connect; only whoever connected it, or the owner, can disconnect. Logged as factory.room_connect / factory.room_disconnect.", "run posts \xAB@plan <your text>\xBB in the room under YOUR name, like typing it in Teams: the same plan, approvals and card. Write it like a ticket: the goal, why, and how you'll know it's done. Any member can run, approve, ask for changes and merge; each one is logged (factory.run, factory.run_approve\u2026).", "card brings the run's live card down to the bottom of its thread; the old one stays as a still footprint linking to the live one. The roles can do it too (factory_card).", "Reading needs membership in the workspace; rename needs owner, admin or Ghosty staff, and is logged (factory.run_rename). The room's card picks the new title up on its next refresh.", "Who is @plan or @build: ghosty agents ls --handle plan --workspace SLUG.", "stats: runs, % merged, median minutes to PR and to merge, @check\u2192@build loops and red CI per run, and cost per run and per merged PR. The cost counts @plan's first turn in the thread, before the run existed.", "--timing reads each role's transcript: engines without one (ACP) show minutes and cost but no commands. It also lists stuck patterns: a command open 8+ min, the same command 4 times, the same error 3 times, going back and forth, or apt install inside a box.", "why: if the run wasn't healthy (stuck patterns, @build over 30 min, loops, red CI, escalated), a category (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), the critical step with its evidence and what to change next time. First it checks the approved plan's criteria against the evidence: approved without the preview a criterion asked for, merged without preview, smoke failed on the merged commit, or a CI criterion with CI none \u2192 approved_unmet_criterion, above any stuck pattern. A healthy run doesn't call the model. When a run closes unhealthy, the room gets this summary in its thread.", "advise: for an ESCALATED run, what to do \u2014 let @build fix it or redo the plan \u2014 with the note for @build point by point (each one cites the finding or plan step behind it) and what @check should review. It compares @check's findings against the signed plan. Nothing is applied: it prints the exact approve/changes command. show tells you why it was escalated.", "While a role works, if it gets stuck the room gets a \u23F3 message in the thread and the role is told what to check; from the second time in the same run, whoever asked gets a push."],
|
|
15046
|
+
notes: ["env: the preview's environment variables live on your computer, so your terminal agent pushes them. ls lists saved and missing names (from .env.example and from runs escalated because the preview won't start); push adds them (only the workspace owner). Use disposable values, never production: the preview runs the repo's code. Values never come back. Then runs recheck <run>: @check reviews the same PR again without another @build loop. Logged as factory.env_set and factory.run_recheck.", "sprints: when the goal is too big for one run, @plan proposes a sprint (3\u20138 tickets in order, with dependencies) as a draft. approve signs every included ticket at once; they start one at a time as their dependencies merge. Only the owner or whoever asked can approve. Logged as factory.sprint_approve.", "rooms repos lists the repos your GitHub App sees (most recent first) and which rooms each one is already in.", "rooms connect checks that YOUR GitHub App installation sees the repo (if not, it gives you the link to grant access) and tells you how ready the repo is for agents (levels 1\u20133 and what's missing). Any member can connect; only whoever connected it, or the owner, can disconnect. Logged as factory.room_connect / factory.room_disconnect.", "run posts \xAB@plan <your text>\xBB in the room under YOUR name, like typing it in Teams: the same plan, approvals and card. Write it like a ticket: the goal, why, and how you'll know it's done. Any member can run, approve, ask for changes and merge; each one is logged (factory.run, factory.run_approve\u2026).", "card brings the run's live card down to the bottom of its thread; the old one stays as a still footprint linking to the live one. The roles can do it too (factory_card).", "Reading needs membership in the workspace; rename needs owner, admin or Ghosty staff, and is logged (factory.run_rename). The room's card picks the new title up on its next refresh.", "Who is @plan or @build: ghosty agents ls --handle plan --workspace SLUG.", "stats: runs, % merged, median minutes to PR and to merge, @check\u2192@build loops and red CI per run, and cost per run and per merged PR. The cost counts @plan's first turn in the thread, before the run existed.", "--timing reads each role's transcript: engines without one (ACP) show minutes and cost but no commands. It also lists stuck patterns: a command open 8+ min, the same command 4 times, the same error 3 times, going back and forth, or apt install inside a box.", "why: if the run wasn't healthy (stuck patterns, @build over 30 min, loops, red CI, escalated), a category (missing_service, unresolved_build_or_tests, fixed_strategy\u2026), the critical step with its evidence and what to change next time. First it checks the approved plan's criteria against the evidence: approved without the preview a criterion asked for, merged without preview, smoke failed on the merged commit, or a CI criterion with CI none \u2192 approved_unmet_criterion, above any stuck pattern. A healthy run doesn't call the model. When a run closes unhealthy, the room gets this summary in its thread.", "advise: for an ESCALATED run, what to do \u2014 let @build fix it or redo the plan \u2014 with the note for @build point by point (each one cites the finding or plan step behind it) and what @check should review. It compares @check's findings against the signed plan. Nothing is applied: it prints the exact approve/changes command. show tells you why it was escalated.", "While a role works, if it gets stuck the room gets a \u23F3 message in the thread and the role is told what to check; from the second time in the same run, whoever asked gets a push.", "choose: when @check escalates a decision it leaves 2\u20133 concrete paths (a, b, c), each one an action: build (@build does it on the branch), recheck, replan, close, merge_as_is or fix_main (opens a separate run that fixes the main branch; this run waits without counting as \xAByour turn\xBB and is updated and re-reviewed on its own when the fix merges). Without a letter it lists them; with one it applies it and the choice reaches the next role word for word. merge_as_is merges with CI as it is (red checks included): use it when what's red isn't caused by the PR; it asks for confirmation and is logged (merge_override). show lists the options too."],
|
|
15045
15047
|
learn: `${REF}#fabrica`
|
|
15046
15048
|
};
|
|
15047
15049
|
function helpText(cmd) {
|
|
@@ -16275,6 +16277,8 @@ Or ask for changes: ghosty factory runs changes ${r.id} --note "\u2026" ${w}`,
|
|
|
16275
16277
|
Firma: ghosty factory runs approve ${r.id} --plan-version ${r.planVersion} ${w}
|
|
16276
16278
|
O pide cambios: ghosty factory runs changes ${r.id} --note "\u2026" ${w}`
|
|
16277
16279
|
);
|
|
16280
|
+
if (r.status === "escalated" && "escalation" in r && r.escalation?.options?.length)
|
|
16281
|
+
return r.escalation.options.map((o) => `${o.id}) ${o.label}: ghosty factory runs choose ${r.id} ${o.id} ${w}`).join("\n");
|
|
16278
16282
|
if (r.status === "escalated" && "escalation" in r && r.escalation?.blocked)
|
|
16279
16283
|
return t(
|
|
16280
16284
|
`@check is blocked by something @build can't provide (e.g. preview variables). Resolve it, then:
|
|
@@ -16473,7 +16477,12 @@ ${dim(`${t("Detail", "Detalle")}: ghosty factory runs show <run> --workspace ${r
|
|
|
16473
16477
|
...r.escalation ? [
|
|
16474
16478
|
bold(red(r.escalation.blocked ? t("@check stopped it: needs something @build can't do", "@check lo fren\xF3: falta algo que @build no puede dar") : t(`@check stopped it after ${r.escalation.loops} loops`, `@check lo fren\xF3 tras ${r.escalation.loops} vueltas`))),
|
|
16475
16479
|
r.escalation.findings,
|
|
16476
|
-
|
|
16480
|
+
...r.escalation.options?.length ? [
|
|
16481
|
+
bold(t("Choose one", "Elige una")),
|
|
16482
|
+
...r.escalation.options.map((o) => ` ${bold(`${o.id})`)} ${o.label} ${dim(`(${o.action})`)}
|
|
16483
|
+
${dim(o.brief)}`),
|
|
16484
|
+
dim(t(`ghosty factory runs choose ${r.id} <letter> --workspace ${ws}`, `ghosty factory runs choose ${r.id} <letra> --workspace ${ws}`))
|
|
16485
|
+
] : [dim(t(`What to do: ghosty factory runs advise ${r.id} --workspace ${ws}`, `Qu\xE9 hacer: ghosty factory runs advise ${r.id} --workspace ${ws}`))]
|
|
16477
16486
|
] : [],
|
|
16478
16487
|
bold(t("Latest events", "\xDAltimos eventos")),
|
|
16479
16488
|
...r.events.map((e) => ` ${dim(short4(e.at))} ${e.type}${e.actor ? ` ${dim(e.actor)}` : ""}`),
|
|
@@ -16518,7 +16527,31 @@ ${dim(t("Dry run: nothing changed.", "Simulacro: no se cambi\xF3 nada."))}`);
|
|
|
16518
16527
|
return out(r, () => `${lavender("\u2713")} ${msg}${verb === "approve" || verb === "changes" || verb === "recheck" ? `
|
|
16519
16528
|
${dim(t(`Follow it: ghosty factory runs watch ${id} --workspace ${ws}`, `S\xEDguelo: ghosty factory runs watch ${id} --workspace ${ws}`))}` : ""}`);
|
|
16520
16529
|
}
|
|
16521
|
-
|
|
16530
|
+
if (verb === "choose") {
|
|
16531
|
+
const id = Number(ref.replace(/^#/, ""));
|
|
16532
|
+
const letter = title?.trim().toLowerCase();
|
|
16533
|
+
const listed = await api(`${base}/${id}/act`, { body: { action: "choose" } });
|
|
16534
|
+
const opt = letter ? listed.options.find((o) => o.id === letter) : null;
|
|
16535
|
+
if (!letter || !opt) {
|
|
16536
|
+
const lines = listed.options.length ? listed.options.map((o) => ` ${bold(`${o.id})`)} ${o.label} ${dim(`(${o.action})`)}
|
|
16537
|
+
${dim(o.brief)}`) : [dim(t("This escalation has no options: use approve --note, changes or advise.", "Este escalado no trae opciones: usa approve --note, changes o advise."))];
|
|
16538
|
+
if (letter) throw usage(t(`#${id} has no option \xAB${letter}\xBB.`, `El #${id} no tiene la opci\xF3n \xAB${letter}\xBB.`), lines.join("\n"));
|
|
16539
|
+
return out(listed, () => lines.join("\n"));
|
|
16540
|
+
}
|
|
16541
|
+
const retry = `ghosty factory runs choose ${id} ${opt.id} --yes --workspace ${ws}`;
|
|
16542
|
+
requireYesIfHeadless(v.yes, retry);
|
|
16543
|
+
await confirm(
|
|
16544
|
+
opt.action === "merge_as_is" ? t(`Merge #${id} with CI as it is (red checks included): \xAB${opt.label}\xBB?`, `\xBFHacer merge del #${id} con el CI como est\xE1 (con checks en rojo): \xAB${opt.label}\xBB?`) : t(`Choose \xAB${opt.id}) ${opt.label}\xBB on #${id}?`, `\xBFElegir \xAB${opt.id}) ${opt.label}\xBB en el #${id}?`),
|
|
16545
|
+
{ yes: v.yes, retry }
|
|
16546
|
+
);
|
|
16547
|
+
const r = await api(`${base}/${id}/act`, { body: { action: "choose", option: opt.id, confirmMerge: opt.action === "merge_as_is" } });
|
|
16548
|
+
return out(
|
|
16549
|
+
r,
|
|
16550
|
+
() => `${lavender("\u2713")} ${r.merged ? t(`#${id} merged.`, `#${id} mergeado.`) : t(`#${id}: chose \xAB${opt.label}\xBB \u2192 ${stage(r.status)}.`, `#${id}: elegiste \xAB${opt.label}\xBB \u2192 ${stage(r.status)}.`)}` + (r.merged ? "" : `
|
|
16551
|
+
${dim(t(`Follow it: ghosty factory runs watch ${id} --workspace ${ws}`, `S\xEDguelo: ghosty factory runs watch ${id} --workspace ${ws}`))}`)
|
|
16552
|
+
);
|
|
16553
|
+
}
|
|
16554
|
+
throw usage(t(`Unknown runs subcommand: ${verb}.`, `Subcomando de runs desconocido: ${verb}.`), 'ghosty factory runs ls | show <run> [--timing] | why <run> [--refresh] | advise <run> | stats [--since 30d] | rename <run> "title" | watch <run> | approve <run> --plan-version N [--note "\u2026"] [--check-scope "\u2026"] | changes <run> --note "\u2026" | recheck <run> | choose <run> [a|b|c] | merge <run> | card <run>');
|
|
16522
16555
|
}
|
|
16523
16556
|
async function agentsByHandle(handle, workspace) {
|
|
16524
16557
|
const qs = new URLSearchParams({ handle, ...workspace ? { workspace } : {} });
|
|
@@ -16528,6 +16561,84 @@ async function agentsByHandle(handle, workspace) {
|
|
|
16528
16561
|
${dim(t(`Couldn't read: ${r.unreadable.join(", ")}`, `No se pudieron leer: ${r.unreadable.join(", ")}`))}` : ""}`);
|
|
16529
16562
|
}
|
|
16530
16563
|
|
|
16564
|
+
// src/commands/events.ts
|
|
16565
|
+
init_api();
|
|
16566
|
+
init_util();
|
|
16567
|
+
init_i18n();
|
|
16568
|
+
var EX2 = 'ghosty events live ls | connect youtube|facebook | prepare --title "\u2026" [--privacy unlisted|public|private] [--at 2026-11-12T19:00] [--only youtube] | check | unlink youtube|facebook [--workspace SLUG]';
|
|
16569
|
+
var enc18 = encodeURIComponent;
|
|
16570
|
+
var NAME = { youtube: "YouTube", facebook: "Facebook" };
|
|
16571
|
+
async function eventsCmd(sub, verb, arg, v, context) {
|
|
16572
|
+
if (sub !== "live") throw usage(t(`Unknown events subcommand: ${sub ?? "(none)"}.`, `Subcomando de events desconocido: ${sub ?? "(ninguno)"}.`), EX2);
|
|
16573
|
+
const ws = v.workspace ?? context;
|
|
16574
|
+
if (!ws) throw usage(t("Which workspace?", "\xBFQu\xE9 espacio?"), t("Add --workspace SLUG (or set one with ghosty use SLUG).", "Agrega --workspace SLUG (o fija uno con ghosty use SLUG)."));
|
|
16575
|
+
const path2 = `/api/v2/workspaces/${enc18(ws)}/live`;
|
|
16576
|
+
const provider = (p) => {
|
|
16577
|
+
if (p !== "youtube" && p !== "facebook") throw usage(t("Which one: youtube or facebook?", "\xBFCu\xE1l: youtube o facebook?"), EX2);
|
|
16578
|
+
return p;
|
|
16579
|
+
};
|
|
16580
|
+
switch (verb ?? "ls") {
|
|
16581
|
+
case "ls":
|
|
16582
|
+
case "check": {
|
|
16583
|
+
const r = await api(`${path2}${verb === "check" ? "?check=1" : ""}`);
|
|
16584
|
+
return out(r, () => {
|
|
16585
|
+
const lines = [];
|
|
16586
|
+
if (!r.destinations.length) lines.push(dim(t(`${r.workspace} has no live destinations. Connect one: ghosty events live connect youtube`, `${r.workspace} no tiene a d\xF3nde transmitir. Conecta uno: ghosty events live connect youtube`)));
|
|
16587
|
+
else
|
|
16588
|
+
lines.push(
|
|
16589
|
+
table(
|
|
16590
|
+
r.destinations.map((d) => ({ where: NAME[d.provider], account: d.account, by: d.connectedBy ?? "", last: d.lastPreparedAt ? `${d.lastPreparedAt.slice(0, 16).replace("T", " ")} ${d.lastWatchUrl ?? ""}` : "" })),
|
|
16591
|
+
["where", "account", "by", "last"]
|
|
16592
|
+
)
|
|
16593
|
+
);
|
|
16594
|
+
if (r.box !== void 0) {
|
|
16595
|
+
if (!r.box) lines.push(red(t("The events box didn't answer.", "La caja de eventos no contest\xF3.")));
|
|
16596
|
+
else lines.push(r.box.ready ? `${lavender("\u2713")} ${t("The events box will stream to", "La caja de eventos transmitir\xE1 a")}: ${bold(r.box.targets.join(" + "))}` : dim(t("The events box has no live destinations loaded: run ghosty events live prepare.", "La caja de eventos no tiene destinos cargados: corre ghosty events live prepare.")));
|
|
16597
|
+
}
|
|
16598
|
+
return lines.join("\n");
|
|
16599
|
+
});
|
|
16600
|
+
}
|
|
16601
|
+
case "connect": {
|
|
16602
|
+
const p = provider(arg);
|
|
16603
|
+
const r = await api(path2, { method: "POST", body: { action: "connect", provider: p, ...v.lang ? { locale: v.lang } : {} } });
|
|
16604
|
+
if (!v["no-open"]) await openUrl(r.url);
|
|
16605
|
+
return out(
|
|
16606
|
+
r,
|
|
16607
|
+
() => [
|
|
16608
|
+
`${lavender("\u2192")} ${t(`Finish connecting ${NAME[p]} in your browser (the link lasts 15 min):`, `Termina de conectar ${NAME[p]} en tu navegador (la liga dura 15 min):`)}`,
|
|
16609
|
+
` ${r.url}`,
|
|
16610
|
+
dim(t("Then check it with: ghosty events live ls", "Luego rev\xEDsalo con: ghosty events live ls"))
|
|
16611
|
+
].join("\n")
|
|
16612
|
+
);
|
|
16613
|
+
}
|
|
16614
|
+
case "unlink": {
|
|
16615
|
+
const p = provider(arg);
|
|
16616
|
+
await confirm(t(`Disconnect ${NAME[p]} from ${ws}? Its events won't stream there anymore.`, `\xBFDesconectar ${NAME[p]} de ${ws}? Sus eventos ya no se transmitir\xE1n ah\xED.`), { yes: v.yes, retry: `ghosty events live unlink ${p} --workspace ${ws} --yes` });
|
|
16617
|
+
const r = await api(path2, { method: "POST", body: { action: "unlink", provider: p } });
|
|
16618
|
+
return out(r, () => r.removed ? `${lavender("\u2713")} ${NAME[p]} ${t("disconnected.", "desconectado.")}` : dim(t(`${NAME[p]} wasn't connected.`, `${NAME[p]} no estaba conectado.`)));
|
|
16619
|
+
}
|
|
16620
|
+
case "prepare": {
|
|
16621
|
+
if (!v.title) throw usage(t("Missing --title (what people will see on YouTube/Facebook).", "Falta --title (lo que ver\xE1 la gente en YouTube/Facebook)."), EX2);
|
|
16622
|
+
if (v.privacy && !["unlisted", "public", "private"].includes(v.privacy)) throw usage("--privacy unlisted|public|private", EX2);
|
|
16623
|
+
const only = v.only ? v.only.split(",").map((x) => provider(x.trim())) : void 0;
|
|
16624
|
+
if (v.force) await confirm(t("--force restarts the events room even with people inside (they get kicked out). Continue?", "--force reinicia la sala de eventos aunque haya gente dentro (los saca). \xBFSeguir?"), { yes: v.yes, retry: `ghosty events live prepare --title "${v.title}" --force --yes` });
|
|
16625
|
+
const r = await api(path2, {
|
|
16626
|
+
method: "POST",
|
|
16627
|
+
body: { action: "prepare", title: v.title, ...v.description ? { description: v.description } : {}, ...v.privacy ? { privacy: v.privacy } : {}, ...v.at ? { startsAt: v.at } : {}, ...only ? { only } : {}, ...v.force ? { force: true } : {} }
|
|
16628
|
+
});
|
|
16629
|
+
return out(r, () => {
|
|
16630
|
+
const lines = r.prepared.map((p) => `${lavender("\u2713")} ${NAME[p.provider]} \xB7 ${p.account}: ${p.watchUrl}`);
|
|
16631
|
+
for (const f of r.failed) lines.push(`${red("\u2717")} ${NAME[f.provider]} \xB7 ${f.account}: ${f.error}`);
|
|
16632
|
+
if (r.box) lines.push(r.box.ready ? `${lavender("\u2713")} ${t("Events box ready to stream to", "Caja de eventos lista para transmitir a")}: ${bold(r.box.targets.join(" + "))}` : red(t("The events box restarted but didn't confirm the destinations: run ghosty events live check.", "La caja de eventos se reinici\xF3 pero no confirm\xF3 los destinos: corre ghosty events live check.")));
|
|
16633
|
+
lines.push(dim(t("In the room, the host presses Record with \xABEn vivo\xBB checked.", "En el room, el anfitri\xF3n aprieta Grabar con \xABEn vivo\xBB marcado.")));
|
|
16634
|
+
return lines.join("\n");
|
|
16635
|
+
});
|
|
16636
|
+
}
|
|
16637
|
+
default:
|
|
16638
|
+
throw usage(t(`Unknown live action: ${verb}.`, `Acci\xF3n desconocida: ${verb}.`), EX2);
|
|
16639
|
+
}
|
|
16640
|
+
}
|
|
16641
|
+
|
|
16531
16642
|
// src/commands/staff.ts
|
|
16532
16643
|
init_api();
|
|
16533
16644
|
init_i18n();
|
|
@@ -16692,7 +16803,7 @@ init_api();
|
|
|
16692
16803
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
16693
16804
|
init_i18n();
|
|
16694
16805
|
init_util();
|
|
16695
|
-
var
|
|
16806
|
+
var enc19 = encodeURIComponent;
|
|
16696
16807
|
var cdmx = (iso) => new Date(Date.parse(iso) - 6 * 36e5).toISOString().slice(5, 16).replace("T", " ");
|
|
16697
16808
|
async function supportThreads(email, v) {
|
|
16698
16809
|
const q = new URLSearchParams({ user: email, since: v.since ?? "30d", ...v.surface ? { surface: v.surface } : {} });
|
|
@@ -16712,7 +16823,7 @@ ${table(rows, ["last", "agent", "conversation", "title", "kind", "listed", "turn
|
|
|
16712
16823
|
${dim(t("Read one: ghosty conversations show <agent> <conversation> --why \xB7 times in CDMX \xB7 listed = in their app list", "Leer uno: ghosty conversations show <agente> <conversaci\xF3n> --why \xB7 horas CDMX \xB7 listed = sale en su lista de la app"))}`);
|
|
16713
16824
|
}
|
|
16714
16825
|
async function supportThread(agent, sid, v) {
|
|
16715
|
-
const r = await api(`/api/v2/support/threads/${
|
|
16826
|
+
const r = await api(`/api/v2/support/threads/${enc19(agent)}/${enc19(sid)}?tail=${enc19(v.limit ?? "40")}${v.tools ? "&tools=1" : ""}`);
|
|
16716
16827
|
out(r, () => {
|
|
16717
16828
|
if (v.tools && r.tools) {
|
|
16718
16829
|
const x = r.tools;
|
|
@@ -16745,7 +16856,7 @@ async function cleanupConversations(action, agent, v) {
|
|
|
16745
16856
|
if (!agent) throw usage(t("Missing agent.", "Falta el agente."), ex);
|
|
16746
16857
|
if (v.kind !== "test" && v.kind !== "channel" && v.kind !== "personal") throw usage(t("--kind takes test, channel or personal.", "--kind acepta test, channel o personal."), ex);
|
|
16747
16858
|
if (action === "rm" && v.kind === "channel") throw usage(t("Customer conversations (channel) are archived, never deleted: their memory keeps serving them.", "Los hilos de clientes (channel) se archivan, nunca se borran: su memoria los sigue atendiendo."), ex);
|
|
16748
|
-
const path2 = `/api/v2/agents/${
|
|
16859
|
+
const path2 = `/api/v2/agents/${enc19(agent)}/conversations/cleanup`;
|
|
16749
16860
|
const body = { kind: v.kind, action, ...v.before ? { before: v.before } : {} };
|
|
16750
16861
|
const plan = await api(path2, { method: "POST", body: { ...body, dryRun: true } });
|
|
16751
16862
|
const verb = action === "rm" ? t("delete (rows + agent memory)", "borrar (filas + memoria del agente)") : t("archive (hidden; memory stays)", "archivar (se ocultan; la memoria se queda)");
|
|
@@ -16760,7 +16871,7 @@ ${t("Go ahead?", "\xBFSigo?")}`, { yes: v.yes, retry: `ghosty conversations ${ac
|
|
|
16760
16871
|
out(r, () => `${lavender("\u2713")} ${t(`${r.threads} conversation(s) ${action === "rm" ? "deleted" : "archived"}.`, `${r.threads} conversaci\xF3n(es) ${action === "rm" ? "borradas" : "archivadas"}.`)}`);
|
|
16761
16872
|
}
|
|
16762
16873
|
async function turnStats(v) {
|
|
16763
|
-
const r = await api(`/api/v2/support/turn-stats?since=${
|
|
16874
|
+
const r = await api(`/api/v2/support/turn-stats?since=${enc19(v.since ?? "14d")}${v.all ? "&all=1" : ""}`);
|
|
16764
16875
|
out(
|
|
16765
16876
|
r,
|
|
16766
16877
|
() => [
|
|
@@ -16780,7 +16891,7 @@ async function fleetBoxes() {
|
|
|
16780
16891
|
${table(rows, ["template", "boxes", "on", "asleep", "ram", "vcpu", "ram on"])}`);
|
|
16781
16892
|
}
|
|
16782
16893
|
async function appAgentsOf(email, client) {
|
|
16783
|
-
const r = await api(`/api/v2/support/app-agents?user=${
|
|
16894
|
+
const r = await api(`/api/v2/support/app-agents?user=${enc19(email)}${client && client !== "all" ? `&client=${enc19(client)}` : ""}`);
|
|
16784
16895
|
const rows = r.agentes.map((a) => ({ id: a.id, name: a.nombre, engine: a.motor ?? "", model: a.modelo ?? "", tone: a.tono ?? t("(by position)", "(por posici\xF3n)"), space: a.espacio?.tipo === "workspace" ? a.espacio.nombre : a.espacio?.tipo ?? "", last: a.ultimaActividad ? cdmx(a.ultimaActividad) : "" }));
|
|
16785
16896
|
const phones = (r.devices ?? []).map((d) => `${d.platform} ${d.appVersion ?? ""}${d.appBuild ? ` (build ${d.appBuild})` : " (build ?)"} \xB7 ${t("seen", "visto")} ${cdmx(d.lastSeenAt)}`.replace(/\s+/g, " "));
|
|
16786
16897
|
out(r, () => `${bold(r.user)} ${dim(r.client ? t(`as the ${r.client} app sees it`, `como lo ve la app de ${r.client}`) : t("all apps", "todas las apps"))}
|
|
@@ -16791,7 +16902,7 @@ ${dim(t("No phones registered for push.", "Sin tel\xE9fonos registrados para avi
|
|
|
16791
16902
|
}
|
|
16792
16903
|
async function pushLog(email, v) {
|
|
16793
16904
|
if (!email) throw usage(t("Missing --user.", "Falta --user."), "ghosty push log --user ana@empresa.com [--since 2d]");
|
|
16794
|
-
const r = await api(`/api/v2/support/push-log?user=${
|
|
16905
|
+
const r = await api(`/api/v2/support/push-log?user=${enc19(email)}&since=${enc19(v.since ?? "2d")}${v.limit ? `&limit=${enc19(v.limit)}` : ""}`);
|
|
16795
16906
|
const rows = r.pushes.map((p) => ({ at: cdmx(p.at), kind: p.kind, to: p.platform, status: p.status === "sent" ? p.status : red(p.status), thread: p.threadKind ? `${p.threadId?.slice(0, 18)} (${p.threadKind})` : (p.threadId ?? "").slice(0, 24), title: (p.title ?? "").slice(0, 40), detail: p.detail ?? "" }));
|
|
16796
16907
|
out(r, () => rows.length ? `${bold(r.user)}
|
|
16797
16908
|
${table(rows, ["at", "kind", "to", "status", "thread", "title", "detail"])}` : dim(t(`No pushes for ${r.user} in that range (logged since 2026-10-01).`, `Sin avisos para ${r.user} en ese rango (se registran desde el 1-oct).`)));
|
|
@@ -16829,24 +16940,24 @@ ${dim(t(`Try it on your phone: ghosty novedades test ${r.id}`, `Pru\xE9bala en t
|
|
|
16829
16940
|
if (!id) throw usage(t("Missing id.", "Falta el id."), ex);
|
|
16830
16941
|
const b = await fields();
|
|
16831
16942
|
if (!Object.keys(b).length) throw usage(t("Nothing to change.", "Nada que cambiar."), ex);
|
|
16832
|
-
const r = await api(`${base}/${
|
|
16943
|
+
const r = await api(`${base}/${enc19(id)}`, { method: "PATCH", body: b });
|
|
16833
16944
|
return out(r, () => `${lavender("\u2713")} ${line2(r)}`);
|
|
16834
16945
|
}
|
|
16835
16946
|
case "test": {
|
|
16836
16947
|
if (!id) throw usage(t("Missing id.", "Falta el id."), ex);
|
|
16837
|
-
const r = await api(`${base}/${
|
|
16948
|
+
const r = await api(`${base}/${enc19(id)}`, { method: "POST", body: { push: "test" } });
|
|
16838
16949
|
return out(r, () => `${lavender("\u2713")} ${t(`Sent to your phone (${r.enviados} device(s)).`, `Enviada a tu tel\xE9fono (${r.enviados} dispositivo(s)).`)}`);
|
|
16839
16950
|
}
|
|
16840
16951
|
case "send":
|
|
16841
16952
|
case "schedule": {
|
|
16842
16953
|
if (!id) throw usage(t("Missing id.", "Falta el id."), ex);
|
|
16843
16954
|
if (v.at !== void 0) {
|
|
16844
|
-
const r2 = await api(`${base}/${
|
|
16955
|
+
const r2 = await api(`${base}/${enc19(id)}`, { method: "PATCH", body: { schedule: v.at || null } });
|
|
16845
16956
|
return out(r2, () => `${lavender("\u2713")} ${line2(r2)}`);
|
|
16846
16957
|
}
|
|
16847
16958
|
requireYesIfHeadless(v.yes, `ghosty novedades send ${id}`);
|
|
16848
16959
|
await confirm(t("Push this announcement to every recipient now?", "\xBFMandar ya el push de esta novedad a todos sus destinatarios?"), { yes: v.yes, retry: `ghosty novedades send ${id}` });
|
|
16849
|
-
const r = await api(`${base}/${
|
|
16960
|
+
const r = await api(`${base}/${enc19(id)}`, { method: "POST", body: { push: "all" } });
|
|
16850
16961
|
return out(r, () => `${lavender("\u2713")} ${t(`Pushed to ${r.enviados} device(s).`, `Enviada a ${r.enviados} dispositivo(s).`)}`);
|
|
16851
16962
|
}
|
|
16852
16963
|
case "rm":
|
|
@@ -16854,7 +16965,7 @@ ${dim(t(`Try it on your phone: ghosty novedades test ${r.id}`, `Pru\xE9bala en t
|
|
|
16854
16965
|
if (!id) throw usage(t("Missing id.", "Falta el id."), ex);
|
|
16855
16966
|
requireYesIfHeadless(v.yes, `ghosty novedades rm ${id}`);
|
|
16856
16967
|
await confirm(t(`Delete announcement ${id}?`, `\xBFBorrar la novedad ${id}?`), { yes: v.yes, retry: `ghosty novedades rm ${id}` });
|
|
16857
|
-
return out(await api(`${base}/${
|
|
16968
|
+
return out(await api(`${base}/${enc19(id)}`, { method: "DELETE" }), () => `${lavender("\u2713")} ${t("Deleted.", "Borrada.")}`);
|
|
16858
16969
|
}
|
|
16859
16970
|
default:
|
|
16860
16971
|
throw usage(t(`Unknown novedades subcommand: ${sub}.`, `Subcomando de novedades desconocido: ${sub}.`), ex);
|
|
@@ -16923,7 +17034,7 @@ ${dim(r.case.id)}`);
|
|
|
16923
17034
|
}
|
|
16924
17035
|
if (!id) throw usage(t("Missing the case id.", "Falta el id del caso."), "ghosty support ls");
|
|
16925
17036
|
if (sub === "show") {
|
|
16926
|
-
const r = v.all ? await api(`/api/v2/support/cases/${
|
|
17037
|
+
const r = v.all ? await api(`/api/v2/support/cases/${enc19(id)}`) : await api(`/api/v2/me/support/${enc19(id)}`);
|
|
16927
17038
|
const c = r.case;
|
|
16928
17039
|
return out(r, () => {
|
|
16929
17040
|
const who2 = (a) => a === "staff" ? "Ghosty" : a === "agent" ? t("agent", "agente") : a === "customer" ? t("customer", "cliente") : a;
|
|
@@ -16944,18 +17055,18 @@ ${m.body}${m.attachments.length ? dim(`
|
|
|
16944
17055
|
}
|
|
16945
17056
|
if (sub === "reply") {
|
|
16946
17057
|
if (!v.body && !v.resolve) throw usage(t("Missing --body.", "Falta --body."), 'ghosty support reply <id> --body "\u2026" [--resolve]');
|
|
16947
|
-
const r = v.all || v.resolve ? await api(`/api/v2/support/cases/${
|
|
17058
|
+
const r = v.all || v.resolve ? await api(`/api/v2/support/cases/${enc19(id)}`, { method: "POST", body: { intent: "reply", body: v.body ?? "", resolve: Boolean(v.resolve) } }) : await api(`/api/v2/me/support/${enc19(id)}`, { method: "POST", body: { body: v.body } });
|
|
16948
17059
|
return out(r, () => `${lavender("\u2713")} ${r.case.code} \xB7 ${STATUS(r.case.status)}`);
|
|
16949
17060
|
}
|
|
16950
17061
|
if (sub === "link") {
|
|
16951
17062
|
const ref = v.ref;
|
|
16952
17063
|
if (!ref) throw usage(t("Missing the issue or PR.", "Falta el issue o PR."), "ghosty support link <id> owner/repo#12 (or the issue/PR URL)");
|
|
16953
|
-
const r = await api(`/api/v2/support/cases/${
|
|
17064
|
+
const r = await api(`/api/v2/support/cases/${enc19(id)}`, { method: "POST", body: { intent: "link", ref } });
|
|
16954
17065
|
return out(r, () => `${lavender("\u2713")} ${r.case.code} \u2192 ${bold(r.ref)} ${dim(`(${r.github.title})`)}${r.alsoWaiting ? `
|
|
16955
17066
|
${dim(t(`${r.alsoWaiting} more cases wait for the same fix: all get "fixed" when it closes.`, `Otros ${r.alsoWaiting} casos esperan el mismo arreglo: a todos les llega \xABya qued\xF3\xBB al cerrarse.`))}` : ""}`);
|
|
16956
17067
|
}
|
|
16957
17068
|
if (sub === "resolve" || sub === "reopen") {
|
|
16958
|
-
const r = await api(`/api/v2/support/cases/${
|
|
17069
|
+
const r = await api(`/api/v2/support/cases/${enc19(id)}`, { method: "POST", body: { intent: sub } });
|
|
16959
17070
|
return out(r, () => `${lavender("\u2713")} ${r.case.code} \xB7 ${STATUS(r.case.status)}`);
|
|
16960
17071
|
}
|
|
16961
17072
|
throw usage(t(`Unknown support subcommand: ${sub}.`, `Subcomando de support desconocido: ${sub}.`), "ghosty support ls | open | show | reply | resolve | reopen | link");
|
|
@@ -17001,6 +17112,7 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
|
|
|
17001
17112
|
coupons redeem <CODE> Redeem a coupon for your account (also /canjear?codigo=CODE)
|
|
17002
17113
|
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]
|
|
17003
17114
|
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]
|
|
17115
|
+
events live ls|connect|prepare|check|unlink Stream a workspace's events to YouTube and a Facebook Page: connect them (OAuth), then "prepare" creates the live event on each and loads the keys in the events room (empty room only) [connect youtube|facebook] [prepare --title "\u2026" --privacy unlisted|public|private --at DATE --only youtube]
|
|
17004
17116
|
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]
|
|
17005
17117
|
factory run "\u2026" --repo o/n [--wait] Hand a request to the Software Factory from the terminal (@plan plans, @build builds, @check reviews); --wait returns when you have to decide [runs watch|approve|changes|merge|card <run>]
|
|
17006
17118
|
factory sprints ls|show|approve The sprints @plan proposes for a bigger goal (3\u20138 tickets in order): list, read, approve with one signature [approve <id> --yes]
|
|
@@ -17220,6 +17332,7 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
|
|
|
17220
17332
|
coupons redeem <C\xD3DIGO> Canjea un cup\xF3n para tu cuenta (tambi\xE9n /canjear?codigo=C\xD3DIGO)
|
|
17221
17333
|
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]
|
|
17222
17334
|
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]
|
|
17335
|
+
events live ls|connect|prepare|check|unlink Transmite los eventos de un espacio a YouTube y a una p\xE1gina de Facebook: con\xE9ctalos (OAuth) y \xABprepare\xBB crea el evento en cada uno y carga las llaves en la sala de eventos (s\xF3lo con la sala vac\xEDa) [connect youtube|facebook] [prepare --title "\u2026" --privacy unlisted|public|private --at FECHA --only youtube]
|
|
17223
17336
|
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]
|
|
17224
17337
|
factory run "\u2026" --repo o/n [--wait] P\xEDdele algo a la Software Factory desde la terminal (@plan planea, @build construye, @check revisa); --wait regresa cuando te toca decidir [runs watch|approve|changes|merge|card <pedido>]
|
|
17225
17338
|
factory sprints ls|show|approve Los sprints que propone @plan para un objetivo grande (3\u20138 tickets en orden): lista, l\xE9elo, apru\xE9balo con una sola firma [approve <id> --yes]
|
|
@@ -17400,7 +17513,7 @@ ${bold("Opciones globales")}
|
|
|
17400
17513
|
${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorrecto \xB7 3 sin sesi\xF3n
|
|
17401
17514
|
${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.")}
|
|
17402
17515
|
${dim("Documentaci\xF3n: https://www.ghosty.studio/docs/cli")}`;
|
|
17403
|
-
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", "watch", "teams", "partner", "image", "tts", "me", "channels", "board", "boards", "access", "credentials", "connectors", "browser", "support", "docs", "help"];
|
|
17516
|
+
var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "settings", "coupons", "ads", "audit", "factory", "events", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "watch", "teams", "partner", "image", "tts", "me", "channels", "board", "boards", "access", "credentials", "connectors", "browser", "support", "docs", "help"];
|
|
17404
17517
|
var AGENTS_SUBS = ["ls", "create", "get", "show", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "embed", "box", "token", "memory", "transfer"];
|
|
17405
17518
|
function unknown(what, input, known, helpCmd) {
|
|
17406
17519
|
const s2 = suggest(input, known);
|
|
@@ -17590,6 +17703,7 @@ async function main() {
|
|
|
17590
17703
|
cap: { type: "string" },
|
|
17591
17704
|
url: { type: "string" },
|
|
17592
17705
|
description: { type: "string" },
|
|
17706
|
+
privacy: { type: "string" },
|
|
17593
17707
|
grant: { type: "string" },
|
|
17594
17708
|
days: { type: "string" },
|
|
17595
17709
|
voice: { type: "string" },
|
|
@@ -17726,7 +17840,7 @@ async function main() {
|
|
|
17726
17840
|
const tokens = splitTokens(pos, v);
|
|
17727
17841
|
globals.token = tokens.session;
|
|
17728
17842
|
globals.profile = v.profile;
|
|
17729
|
-
if (v.version) return out({ version: "0.
|
|
17843
|
+
if (v.version) return out({ version: "0.93.1" }, () => "0.93.1");
|
|
17730
17844
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
17731
17845
|
const context = (await readConfig()).workspace;
|
|
17732
17846
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -17907,6 +18021,8 @@ async function main() {
|
|
|
17907
18021
|
return auditCmd(sub, v, context);
|
|
17908
18022
|
case "factory":
|
|
17909
18023
|
return factoryCmd(sub, a1, a2, pos[4], v, context);
|
|
18024
|
+
case "events":
|
|
18025
|
+
return eventsCmd(sub, a1, a2, v, context);
|
|
17910
18026
|
case "plan":
|
|
17911
18027
|
if (sub === "open") {
|
|
17912
18028
|
const slug = a1 ?? context;
|
|
@@ -17929,7 +18045,7 @@ async function main() {
|
|
|
17929
18045
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
17930
18046
|
}
|
|
17931
18047
|
}
|
|
17932
|
-
var notice = updateNotice("0.
|
|
18048
|
+
var notice = updateNotice("0.93.1").catch(() => null);
|
|
17933
18049
|
main().then(
|
|
17934
18050
|
async () => {
|
|
17935
18051
|
const n = process.stderr.isTTY ? await notice : null;
|
package/package.json
CHANGED