@ghostystudio/cli 0.41.1 → 0.42.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 +5 -1
- package/dist/index.js +84 -37
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ ghosty apply <file|dir> [--agent X] [--create] [--prune] [--dry-run] # make an
|
|
|
30
30
|
ghosty agents set <id> [--name] [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,…] [--connect ID,…] [--disconnect ID,…] [--toolsets +crm]
|
|
31
31
|
ghosty agents set <id> --prompt-base <base-id> --prompt-overlay overlay.json [--dry-run] # prompt = another agent's + edits, kept in sync
|
|
32
32
|
ghosty agents share|unshare <id> <email> [--role editor|admin] # share without handing it over · agents shares <id> lists them
|
|
33
|
-
ghosty agents teams ls|on|off <id> [workspace] [--handle x] # which Teams workspaces it answers in, and its @handle there
|
|
33
|
+
ghosty agents teams ls|on|off|rm <id> [workspace] [--handle x] # which Teams workspaces it answers in, and its @handle there
|
|
34
34
|
ghosty agents rm <id> [--from-workspace] [--yes] # --from-workspace: turn it off in Teams first
|
|
35
35
|
ghosty agents set <id> [--tool wa:tool=off,…] [--bag NAME|none] [--avatar URL|FILE]
|
|
36
36
|
ghosty agents restart <id>
|
|
@@ -101,6 +101,10 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
|
|
|
101
101
|
|
|
102
102
|
Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
|
|
103
103
|
|
|
104
|
+
### Changes in 0.42.0
|
|
105
|
+
|
|
106
|
+
- `agents teams off` now **pauses** the agent in that workspace (it keeps its `@handle`; `on` resumes it). `agents teams rm <id> <workspace> [--yes]` removes it and frees the handle. `ls` shows `paused` and the workspaces where it was activated by someone else (read-only). Without `--handle`, `on` reuses the handle it already has in your other workspaces.
|
|
107
|
+
|
|
104
108
|
### Changes in 0.41.1
|
|
105
109
|
|
|
106
110
|
- `agents teams`: the agent can be given by name (0.41.0 read `ls`/`on`/`off` as the agent).
|
package/dist/index.js
CHANGED
|
@@ -7469,7 +7469,7 @@ var SERVER_MESSAGES = [
|
|
|
7469
7469
|
["s\xF3lo el due\xF1o del agente lo activa en sus equipos", "only the agent's owner turns it on in their workspaces"],
|
|
7470
7470
|
["s\xF3lo el due\xF1o del agente o staff lo activan en Teams", "only the agent's owner or staff turn it on in Teams"],
|
|
7471
7471
|
["falta workspace (el slug del equipo)", "missing workspace (the workspace slug)"],
|
|
7472
|
-
["Ese agente est\xE1 activo en {}.
|
|
7472
|
+
["Ese agente est\xE1 activo en {}. Qu\xEDtalo de ah\xED (Canales \u2192 Ghosty Teams) antes de borrarlo.", "That agent is active in {}. Remove it from there (Channels \u2192 Ghosty Teams) before deleting it."],
|
|
7473
7473
|
["sin cupo para otro agente ahora", "no room for another agent right now"],
|
|
7474
7474
|
["Tu plan incluye 1 agente.", "Your plan includes 1 agent."],
|
|
7475
7475
|
["Tu plan incluye {} agentes.", "Your plan includes {} agents."],
|
|
@@ -8422,7 +8422,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
|
|
|
8422
8422
|
const req = httpsRequest(`${base}${path}`, {
|
|
8423
8423
|
method: "POST",
|
|
8424
8424
|
timeout: timeoutMs,
|
|
8425
|
-
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.
|
|
8425
|
+
headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.42.1"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
|
|
8426
8426
|
}, (res) => {
|
|
8427
8427
|
let buf = "";
|
|
8428
8428
|
res.on("data", (c) => buf += c);
|
|
@@ -8464,7 +8464,7 @@ async function request(path, opts = {}, retried = false) {
|
|
|
8464
8464
|
method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
|
|
8465
8465
|
headers: {
|
|
8466
8466
|
authorization: `Bearer ${token}`,
|
|
8467
|
-
"user-agent": `ghosty-cli/${"0.
|
|
8467
|
+
"user-agent": `ghosty-cli/${"0.42.1"}`,
|
|
8468
8468
|
"accept-language": lang(),
|
|
8469
8469
|
...opts.body !== void 0 ? { "content-type": "application/json" } : {},
|
|
8470
8470
|
...opts.headers
|
|
@@ -8910,22 +8910,32 @@ ${rows.length ? table(rows, ["email", "role", "accepted"]) : dim(t("Not shared w
|
|
|
8910
8910
|
out(r, () => `${lavender("\u2713")} ${r.already ? t(`Already shared with ${r.email}`, `Ya estaba compartido con ${r.email}`) : t(`Shared with ${r.email}; they got an email`, `Compartido con ${r.email}; le lleg\xF3 un correo`)} ${dim(`(${r.role})`)}.`);
|
|
8911
8911
|
}
|
|
8912
8912
|
async function agentsTeams(sub, id, ws, v) {
|
|
8913
|
-
const ex = "ghosty agents teams ls <agent-id> \xB7 on <agent-id> <workspace> [--handle x] \xB7 off <agent-id> <workspace>";
|
|
8914
|
-
if (sub !== "ls" && sub !== "on" && sub !== "off") throw usage(t("Use ls, on or
|
|
8913
|
+
const ex = "ghosty agents teams ls <agent-id> \xB7 on <agent-id> <workspace> [--handle x] \xB7 off <agent-id> <workspace> \xB7 rm <agent-id> <workspace> [--yes]";
|
|
8914
|
+
if (sub !== "ls" && sub !== "on" && sub !== "off" && sub !== "rm") throw usage(t("Use ls, on, off or rm.", "Usa ls, on, off o rm."), ex);
|
|
8915
8915
|
id = need(id, "agent id", ex);
|
|
8916
8916
|
if (sub === "ls") {
|
|
8917
8917
|
const r2 = await api(agentPath(id, "/teams"));
|
|
8918
|
-
const
|
|
8919
|
-
|
|
8920
|
-
|
|
8921
|
-
|
|
8922
|
-
|
|
8918
|
+
const label = { on: t("on", "prendido"), paused: t("paused", "en pausa"), off: t("off", "apagado") };
|
|
8919
|
+
const rows = r2.teams.map((x) => {
|
|
8920
|
+
const state = x.state ?? (x.active ? "on" : "off");
|
|
8921
|
+
return {
|
|
8922
|
+
workspace: x.slug,
|
|
8923
|
+
handle: state === "off" ? dim(`(@${x.suggested})`) : `@${x.handle}`,
|
|
8924
|
+
state: !x.confirmed ? t("unconfirmed", "sin confirmar") : label[state] + (x.editable === false ? dim(t(" \xB7 not yours to change", " \xB7 no lo administras")) : "")
|
|
8925
|
+
};
|
|
8926
|
+
});
|
|
8923
8927
|
return out(r2, () => rows.length ? table(rows, ["workspace", "handle", "state"]) : dim(t("You don't administer any Teams workspace yet.", "A\xFAn no administras ning\xFAn equipo de Teams.")));
|
|
8924
8928
|
}
|
|
8925
8929
|
const workspace = need(ws ?? v.workspace, "workspace", ex);
|
|
8930
|
+
if (sub === "rm") {
|
|
8931
|
+
requireYesIfHeadless(v.yes, `ghosty agents teams rm ${id} ${workspace}`);
|
|
8932
|
+
if (!v.yes) await confirm(t(`Remove it from ${workspace}? It frees its @handle there; the agent stays.`, `\xBFQuitarlo de ${workspace}? Suelta su @handle ah\xED; el agente sigue.`), { retry: `ghosty agents teams rm ${id} ${workspace} --yes` });
|
|
8933
|
+
const r2 = await api(agentPath(id, `/teams?workspace=${encodeURIComponent(workspace)}&remove=1`), { method: "DELETE", body: { workspace, remove: true } });
|
|
8934
|
+
return out(r2, () => `${lavender("\u2713")} ${r2.wasThere ? t(`Removed from ${workspace}.`, `Quitado de ${workspace}.`) : t(`It wasn't in ${workspace}.`, `No estaba en ${workspace}.`)}`);
|
|
8935
|
+
}
|
|
8926
8936
|
if (sub === "off") {
|
|
8927
8937
|
const r2 = await api(agentPath(id, `/teams?workspace=${encodeURIComponent(workspace)}`), { method: "DELETE", body: { workspace } });
|
|
8928
|
-
return out(r2, () => `${lavender("\u2713")} ${r2.wasActive ? t(`
|
|
8938
|
+
return out(r2, () => `${lavender("\u2713")} ${r2.wasActive ? t(`Paused in ${workspace}; it keeps its @handle.`, `En pausa en ${workspace}; conserva su @handle.`) : t(`It wasn't answering in ${workspace}.`, `No estaba contestando en ${workspace}.`)}`);
|
|
8929
8939
|
}
|
|
8930
8940
|
const r = await api(agentPath(id, "/teams"), { method: "POST", body: { workspace, ...v.handle ? { handle: v.handle } : {} } });
|
|
8931
8941
|
out(r, () => `${lavender("\u2713")} ${r.changed ? t(`Answers in ${workspace} as @${r.handle}.`, `Contesta en ${workspace} como @${r.handle}.`) : t(`Already answering in ${workspace} as @${r.handle}.`, `Ya contestaba en ${workspace} como @${r.handle}.`)}`);
|
|
@@ -9263,26 +9273,61 @@ async function turn(agent, sid, text, first, images = []) {
|
|
|
9263
9273
|
let answer = "";
|
|
9264
9274
|
let usageData;
|
|
9265
9275
|
let ours = false;
|
|
9276
|
+
let terminado = false;
|
|
9277
|
+
let stream = res;
|
|
9266
9278
|
try {
|
|
9267
9279
|
await sent;
|
|
9268
|
-
for
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
|
|
9281
|
-
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9280
|
+
for (let intento = 0; ; intento++) {
|
|
9281
|
+
let recibido = "";
|
|
9282
|
+
try {
|
|
9283
|
+
for await (const ev of readSse(stream.body)) {
|
|
9284
|
+
const d = parseData(ev);
|
|
9285
|
+
if (intento > 0 && ev.event === "done" && d.reposo) {
|
|
9286
|
+
if (d.interrumpido?.turnId === turnId) throw new CliError(serverText(d.interrumpido.motivo ?? t("The turn was cut off.", "El turno se cort\xF3.")), EXIT.API);
|
|
9287
|
+
if (d.ultimo?.turnId === turnId && d.ultimo.text) recibido = d.ultimo.text;
|
|
9288
|
+
else if (!ours) {
|
|
9289
|
+
terminado = true;
|
|
9290
|
+
break;
|
|
9291
|
+
}
|
|
9292
|
+
}
|
|
9293
|
+
if (d.turnId) ours = d.turnId === turnId;
|
|
9294
|
+
if (!ours && !(intento > 0 && ev.event === "done" && d.reposo)) continue;
|
|
9295
|
+
if (ev.event === "chunk" && d.text) recibido += d.text;
|
|
9296
|
+
if (ev.event === "reemplazo" && d.text) {
|
|
9297
|
+
answer = recibido = d.text;
|
|
9298
|
+
continue;
|
|
9299
|
+
}
|
|
9300
|
+
if ((ev.event === "chunk" || ev.event === "done") && recibido.length > answer.length && recibido.startsWith(answer)) {
|
|
9301
|
+
const nuevo = recibido.slice(answer.length);
|
|
9302
|
+
answer = recibido;
|
|
9303
|
+
if (globals.json) process.stdout.write(JSON.stringify({ event: "chunk", text: nuevo }) + "\n");
|
|
9304
|
+
else process.stdout.write(nuevo);
|
|
9305
|
+
}
|
|
9306
|
+
if (ev.event === "tool" && d.title) {
|
|
9307
|
+
if (globals.json) process.stdout.write(JSON.stringify({ event: "tool", ...d }) + "\n");
|
|
9308
|
+
else if (!d.status || d.status === "pending" || d.status === "in_progress") info(dim(` \u2699 ${serverText(d.title)}`));
|
|
9309
|
+
} else if (ev.event === "usage") {
|
|
9310
|
+
usageData = d;
|
|
9311
|
+
} else if (ev.event === "error") {
|
|
9312
|
+
throw new CliError(d.message ? serverText(d.message) : t("The turn failed.", "El turno fall\xF3."), EXIT.API);
|
|
9313
|
+
} else if (ev.event === "done") {
|
|
9314
|
+
terminado = true;
|
|
9315
|
+
break;
|
|
9316
|
+
}
|
|
9317
|
+
}
|
|
9318
|
+
} catch (e) {
|
|
9319
|
+
if (e instanceof CliError || cancelled) throw e;
|
|
9320
|
+
}
|
|
9321
|
+
if (terminado || cancelled) break;
|
|
9322
|
+
if (intento >= 5) {
|
|
9323
|
+
throw new CliError(
|
|
9324
|
+
t(`Lost the connection to the turn; it may still be running. Check: ghosty conversations show ${agent} ${sid}`, `Se perdi\xF3 la conexi\xF3n con el turno; puede seguir corriendo. Revisa: ghosty conversations show ${agent} ${sid}`),
|
|
9325
|
+
EXIT.API
|
|
9326
|
+
);
|
|
9285
9327
|
}
|
|
9328
|
+
await new Promise((r) => setTimeout(r, Math.min(5e3, 1e3 * (intento + 1))));
|
|
9329
|
+
if (!globals.json) info(dim(t("(reconnecting\u2026)", "(reconectando\u2026)")));
|
|
9330
|
+
stream = await request(convPath(agent, `/${enc3(sid)}/events`), { signal: ctrl.signal, headers: { accept: "text/event-stream" } });
|
|
9286
9331
|
}
|
|
9287
9332
|
} finally {
|
|
9288
9333
|
process.off("SIGINT", onSigint);
|
|
@@ -9671,7 +9716,7 @@ async function call(path, v, init = {}) {
|
|
|
9671
9716
|
"x-ghosty-ts": ts,
|
|
9672
9717
|
"x-ghosty-sig": sig,
|
|
9673
9718
|
"content-type": "application/json",
|
|
9674
|
-
"user-agent": `ghosty-cli/${"0.
|
|
9719
|
+
"user-agent": `ghosty-cli/${"0.42.1"}`
|
|
9675
9720
|
},
|
|
9676
9721
|
body: method === "GET" ? void 0 : raw
|
|
9677
9722
|
});
|
|
@@ -10980,9 +11025,10 @@ var HELPS_ES = {
|
|
|
10980
11025
|
["# your account: merge copies with the same content", "# tu cuenta: une las copias con el mismo contenido"],
|
|
10981
11026
|
["# staff: their agents, latest turns, plan and boxes", "# staff: sus agentes, \xFAltimos turnos, plan y cajas"],
|
|
10982
11027
|
["# what it really has: effective toolsets, connectors connected + granted", "# lo que de verdad tiene: toolsets efectivos, conectores conectados + concedidos"],
|
|
10983
|
-
["# Teams workspaces you administer: where it answers and with which @handle", "# los equipos de Teams que administras: d\xF3nde contesta y con qu\xE9 @handle"],
|
|
11028
|
+
["# Teams workspaces you administer: where it answers, is paused, and with which @handle", "# los equipos de Teams que administras: d\xF3nde contesta, d\xF3nde est\xE1 en pausa y con qu\xE9 @handle"],
|
|
10984
11029
|
["# turn it on there (or change its @handle)", "# lo prende ah\xED (o le cambia el @handle)"],
|
|
10985
|
-
["#
|
|
11030
|
+
["# pause it there; it keeps its @handle", "# lo pausa ah\xED; conserva su @handle"],
|
|
11031
|
+
["# remove it from there; the agent stays", "# lo quita de ah\xED; el agente sigue"]
|
|
10986
11032
|
],
|
|
10987
11033
|
flags: [
|
|
10988
11034
|
["--fields a,b", "get: regresa s\xF3lo estos campos"],
|
|
@@ -11383,9 +11429,10 @@ var HELPS = {
|
|
|
11383
11429
|
"ghosty agents share <agent-id> <email> [--role editor|admin]",
|
|
11384
11430
|
"ghosty agents unshare <agent-id> <email> [--yes]",
|
|
11385
11431
|
"ghosty agents shares <agent-id>",
|
|
11386
|
-
"ghosty agents teams ls <agent-id> # Teams workspaces you administer: where it answers and with which @handle",
|
|
11432
|
+
"ghosty agents teams ls <agent-id> # Teams workspaces you administer: where it answers, is paused, and with which @handle",
|
|
11387
11433
|
"ghosty agents teams on <agent-id> <workspace> [--handle NAME] # turn it on there (or change its @handle)",
|
|
11388
|
-
"ghosty agents teams off <agent-id> <workspace> #
|
|
11434
|
+
"ghosty agents teams off <agent-id> <workspace> # pause it there; it keeps its @handle",
|
|
11435
|
+
"ghosty agents teams rm <agent-id> <workspace> [--yes] # remove it from there; the agent stays",
|
|
11389
11436
|
"ghosty agents restart <agent-id>",
|
|
11390
11437
|
"ghosty agents box <agent-id> [--check PATH]\u2026 [--contains PATH=TEXT]\u2026 [--recycle]",
|
|
11391
11438
|
"ghosty agents demo enable|disable <agent-id>",
|
|
@@ -13029,7 +13076,7 @@ ${bold("Agents")}
|
|
|
13029
13076
|
agents docs replace <id> <doc> New version (keeps name and access) --url URL | --file PATH [--note]
|
|
13030
13077
|
agents docs history|restore <id> <doc> [n] Its versions; restore n as a new version
|
|
13031
13078
|
agents share|unshare <id> <email> Share it without handing it over [--role editor|admin] \xB7 agents shares <id> lists them
|
|
13032
|
-
agents teams ls|on|off <id> [ws]
|
|
13079
|
+
agents teams ls|on|off|rm <id> [ws] Which Teams workspaces it answers in, and its @handle there [--handle x]
|
|
13033
13080
|
agents rm <id> Delete an agent (owner only; asks you to type its name, or --yes) [--from-workspace: turn it off in Teams first]
|
|
13034
13081
|
agents restart <id> Restart an ACP agent (needsRestart) so it loads new skills
|
|
13035
13082
|
agents box <id> The machine serving it: is it on the new image? [--check PATH]\u2026 [--contains PATH=TEXT]\u2026 [--recycle [--reenv] [--force]]
|
|
@@ -13165,7 +13212,7 @@ ${bold("Agentes")}
|
|
|
13165
13212
|
agents docs replace <id> <doc> Versi\xF3n nueva (conserva nombre y accesos) --url URL | --file RUTA [--note]
|
|
13166
13213
|
agents docs history|restore <id> <doc> [n] Sus versiones; restaura la n como versi\xF3n nueva
|
|
13167
13214
|
agents share|unshare <id> <correo> Comp\xE1rtelo sin cederlo [--role editor|admin] \xB7 agents shares <id> los lista
|
|
13168
|
-
agents teams ls|on|off <id> [equipo] En qu\xE9 equipos de Teams contesta y con qu\xE9 @handle [--handle x]
|
|
13215
|
+
agents teams ls|on|off|rm <id> [equipo] En qu\xE9 equipos de Teams contesta y con qu\xE9 @handle [--handle x]
|
|
13169
13216
|
agents rm <id> Borra un agente (s\xF3lo el due\xF1o; te pide escribir su nombre, o --yes) [--from-workspace: antes lo desactiva en Teams]
|
|
13170
13217
|
agents restart <id> Reinicia un agente ACP (needsRestart) para que cargue skills nuevas
|
|
13171
13218
|
agents box <id> La m\xE1quina que lo atiende: \xBFya trae la imagen nueva? [--check RUTA]\u2026 [--contains RUTA=TEXTO]\u2026 [--recycle [--reenv] [--force]]
|
|
@@ -13478,7 +13525,7 @@ async function main() {
|
|
|
13478
13525
|
const tokens = splitTokens(pos, v);
|
|
13479
13526
|
globals.token = tokens.session;
|
|
13480
13527
|
globals.profile = v.profile;
|
|
13481
|
-
if (v.version) return out({ version: "0.
|
|
13528
|
+
if (v.version) return out({ version: "0.42.1" }, () => "0.42.1");
|
|
13482
13529
|
for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
|
|
13483
13530
|
const context = (await readConfig()).workspace;
|
|
13484
13531
|
if (!explicitToken()?.startsWith("gat_")) {
|
|
@@ -13631,7 +13678,7 @@ async function main() {
|
|
|
13631
13678
|
throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
|
|
13632
13679
|
}
|
|
13633
13680
|
}
|
|
13634
|
-
var notice = updateNotice("0.
|
|
13681
|
+
var notice = updateNotice("0.42.1").catch(() => null);
|
|
13635
13682
|
main().then(
|
|
13636
13683
|
async () => {
|
|
13637
13684
|
const n = await notice;
|
package/package.json
CHANGED