@ghostystudio/cli 0.50.0 → 0.51.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 CHANGED
@@ -38,6 +38,8 @@ ghosty agents box <id> [--check PATH]… [--contains PATH=TEXT]… [--recycle]
38
38
  ghosty agents demo enable|disable <id>
39
39
  ghosty agents demo <id> [--slug NAME] [--expires "YYYY-MM-DDTHH:MM"|no] [--turns N] [--per-ip N]
40
40
  [--welcome TEXT] [--starter TEXT] [--chips "a|b|c"] [--sponsor on|off] [--rotate] # public /p/ link, no account needed
41
+ ghosty agents embed enable|disable <id> [--domains a.com,*.b.com] # web widget: chat bubble on your site, only on those domains
42
+ ghosty agents embed <id> [--per-visitor N] [--per-ip N] [--welcome TEXT] [--color #hex] [--rotate] # state + the <script> to paste
41
43
  ghosty agents doctor <id> [--verbose] # exits 1 when it finds a problem
42
44
  ghosty agents docs ls|grant|revoke <id> [doc] [--write] [--no-deliver]
43
45
  ghosty agents docs add <id> --url URL | --file PATH [--description TEXT] [--grant read|write|no]
@@ -103,6 +105,10 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
103
105
 
104
106
  Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
105
107
 
108
+ ### Changes in 0.51.0
109
+
110
+ - `agents embed enable|disable <id> [--domains a.com,*.b.com] [--per-visitor N] [--per-ip N] [--welcome T] [--color #hex] [--rotate]`: the **web widget**, a chat bubble with the agent on your own site (one `<script>`), loading only on the domains you list; each visitor gets an isolated conversation and talks as a customer. Claude engine only. No flags = state + the snippet.
111
+
106
112
  ### Changes in 0.50.0
107
113
 
108
114
  - `cards pause|resume <id> <card> [--mode 30min|2h|24h|until_tomorrow|permanent]`: the thread's pause menu; resume also lifts "operator only" and doesn't answer by itself. Logged.
package/dist/index.js CHANGED
@@ -8164,7 +8164,12 @@ var SERVER_MESSAGES = [
8164
8164
  ["s\xF3lo el due\xF1o de \xAB{}\xBB o el staff de Ghosty leen su bit\xE1cora", "only \xAB{}\xBB's owner or Ghosty staff read its audit log"],
8165
8165
  ["s\xF3lo aplica a conversaciones de WhatsApp Business", "only applies to WhatsApp Business conversations"],
8166
8166
  ["ese n\xFAmero ya no est\xE1 conectado", "that number is no longer connected"],
8167
- ["ese n\xFAmero no es de este tablero", "that number isn't on this board"]
8167
+ ["ese n\xFAmero no es de este tablero", "that number isn't on this board"],
8168
+ // — Widget web (`agents embed`)
8169
+ ["s\xF3lo el due\xF1o del agente maneja su widget web", "only the agent's owner manages its web widget"],
8170
+ ["dominio no v\xE1lido: {} (usa ejemplo.com o *.ejemplo.com, sin https:// ni rutas)", "invalid domain: {} (use example.com or *.example.com, no https:// or paths)"],
8171
+ ["el widget web s\xF3lo corre con motor claude (es el que a\xEDsla a cada visitante)", "the web widget only runs on the claude engine (it's the one that isolates each visitor)"],
8172
+ ["pon al menos un dominio donde va a vivir el widget (--domains ejemplo.com)", "add at least one domain where the widget will live (--domains example.com)"]
8168
8173
  ];
8169
8174
 
8170
8175
  // src/i18n.ts
@@ -8463,7 +8468,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
8463
8468
  const req = httpsRequest(`${base}${path}`, {
8464
8469
  method: "POST",
8465
8470
  timeout: timeoutMs,
8466
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.50.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8471
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.51.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8467
8472
  }, (res) => {
8468
8473
  let buf = "";
8469
8474
  res.on("data", (c) => buf += c);
@@ -8505,7 +8510,7 @@ async function request(path, opts = {}, retried = false) {
8505
8510
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
8506
8511
  headers: {
8507
8512
  authorization: `Bearer ${token}`,
8508
- "user-agent": `ghosty-cli/${"0.50.0"}`,
8513
+ "user-agent": `ghosty-cli/${"0.51.0"}`,
8509
8514
  "accept-language": lang(),
8510
8515
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
8511
8516
  ...opts.headers
@@ -9339,6 +9344,33 @@ async function agentsDemo(id, v) {
9339
9344
  ].join("\n")
9340
9345
  );
9341
9346
  }
9347
+ async function agentsEmbed(id, v) {
9348
+ id = need(id, "agent id", "ghosty agents embed enable <agent-id> --domains tusitio.com");
9349
+ if (v.on && v.off) throw usage(t("Use enable or disable, not both.", "Usa enable o disable, no los dos."));
9350
+ const body = {};
9351
+ if (v.on) body.enabled = true;
9352
+ if (v.off) body.enabled = false;
9353
+ if (v.domains !== void 0) body.domains = v.domains.split(/[\s,]+/).map((d) => d.trim()).filter(Boolean);
9354
+ if (v["per-visitor"]) body.perVisitorDay = Number(v["per-visitor"]);
9355
+ if (v["per-ip"]) body.perIpDay = Number(v["per-ip"]);
9356
+ if (v.welcome !== void 0) body.welcome = v.welcome || null;
9357
+ if (v.color !== void 0) body.color = v.color;
9358
+ if (v.rotate) body.rotate = true;
9359
+ const e = Object.keys(body).length ? await api(agentPath(id, "/embed"), { method: "PUT", body }) : await api(agentPath(id, "/embed"));
9360
+ out(
9361
+ e,
9362
+ () => [
9363
+ `${e.enabled ? lavender(t("\u25CF on", "\u25CF encendido")) : dim(t("\u25CB off", "\u25CB apagado"))} ${t("web widget", "widget web")}`,
9364
+ e.domains.length ? `${t("domains", "dominios")}: ${e.domains.join(", ")}` : red(t("domains: (none \u2014 it loads nowhere; add --domains yoursite.com)", "dominios: (ninguno \u2014 no carga en ning\xFAn lado; agrega --domains tusitio.com)")),
9365
+ ...e.engineOk ? [] : [red(t("engine: only claude isolates each visitor; switch with `ghosty agents set <id> --engine claude`", "motor: s\xF3lo claude a\xEDsla a cada visitante; c\xE1mbialo con `ghosty agents set <id> --engine claude`"))],
9366
+ dim(t(`cap ${e.perVisitorDay} messages per visitor per day \xB7 ${e.perIpDay} per IP per day \xB7 color ${e.color}`, `tope ${e.perVisitorDay} mensajes por visitante al d\xEDa \xB7 ${e.perIpDay} por IP al d\xEDa \xB7 color ${e.color}`)),
9367
+ e.welcome ? `${t("welcome", "bienvenida")}: ${e.welcome}` : dim(t("welcome: (default greeting)", "bienvenida: (saludo por defecto)")),
9368
+ ...e.snippet ? ["", t("Paste before </body> on your site:", "Pega antes de </body> en tu sitio:"), e.snippet, ""] : [],
9369
+ t(`visitors ${e.stats.visitantes} \xB7 messages ${e.stats.mensajes}`, `visitantes ${e.stats.visitantes} \xB7 mensajes ${e.stats.mensajes}`),
9370
+ ...e.lastError ? [red(`${t("last failure", "\xFAltima falla")} ${e.lastError.at}: ${serverText(e.lastError.message ?? e.lastError.error ?? "")}`)] : []
9371
+ ].join("\n")
9372
+ );
9373
+ }
9342
9374
  async function agentsBox(id, v) {
9343
9375
  id = need(id, "agent id", "ghosty agents box <agent-id> [--check PATH] [--contains PATH=TEXT] [--recycle]");
9344
9376
  if (v.recycle) {
@@ -9950,7 +9982,7 @@ async function call(path, v, init = {}) {
9950
9982
  "x-ghosty-ts": ts,
9951
9983
  "x-ghosty-sig": sig,
9952
9984
  "content-type": "application/json",
9953
- "user-agent": `ghosty-cli/${"0.50.0"}`
9985
+ "user-agent": `ghosty-cli/${"0.51.0"}`
9954
9986
  },
9955
9987
  body: method === "GET" ? void 0 : raw
9956
9988
  });
@@ -11563,7 +11595,9 @@ var HELPS_ES = {
11563
11595
  ["# 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"],
11564
11596
  ["# turn it on there (or change its @handle)", "# lo prende ah\xED (o le cambia el @handle)"],
11565
11597
  ["# pause it there; it keeps its @handle", "# lo pausa ah\xED; conserva su @handle"],
11566
- ["# remove it from there; the agent stays", "# lo quita de ah\xED; el agente sigue"]
11598
+ ["# remove it from there; the agent stays", "# lo quita de ah\xED; el agente sigue"],
11599
+ ["# web widget: chat bubble on your site, only on those domains", "# widget web: burbuja de chat en tu sitio, s\xF3lo en esos dominios"],
11600
+ ["# state + the <script> to paste", "# su estado + el <script> para pegar"]
11567
11601
  ],
11568
11602
  flags: [
11569
11603
  ["--fields a,b", "get: regresa s\xF3lo estos campos"],
@@ -12065,6 +12099,8 @@ var HELPS = {
12065
12099
  "ghosty agents box <agent-id> [--check PATH]\u2026 [--contains PATH=TEXT]\u2026 [--recycle]",
12066
12100
  "ghosty agents demo enable|disable <agent-id>",
12067
12101
  'ghosty agents demo <agent-id> [--slug NAME] [--expires "YYYY-MM-DDTHH:MM"|no] [--turns N] [--per-ip N] [--welcome TEXT] [--starter TEXT] [--chips "a|b|c"] [--sponsor on|off] [--rotate]',
12102
+ "ghosty agents embed enable|disable <agent-id> [--domains a.com,*.b.com] # web widget: chat bubble on your site, only on those domains",
12103
+ "ghosty agents embed <agent-id> [--domains \u2026] [--per-visitor N] [--per-ip N] [--welcome TEXT] [--color #hex] [--rotate] # state + the <script> to paste",
12068
12104
  "ghosty agents rm <agent-id> [--from-workspace] [--yes]"
12069
12105
  ],
12070
12106
  flags: [
@@ -12143,6 +12179,7 @@ var HELPS = {
12143
12179
  "ghosty agents set <pia-id> --prompt-base <tania-id> --prompt-overlay capa.json --dry-run --out /tmp/pia.md",
12144
12180
  "ghosty agents demo enable <id>",
12145
12181
  'ghosty agents demo <id> --slug guardias --expires "2026-10-15T20:00" --starter "Ens\xE9\xF1ame c\xF3mo empezar"',
12182
+ 'ghosty agents embed enable <id> --domains "mitienda.com,*.mitienda.mx" --welcome "\xA1Hola! \xBFEn qu\xE9 te ayudo?"',
12146
12183
  "ghosty agents box <id> --contains /opt/claude-worker/skills/pdf-doc/render-doc.mjs=pdf-templates",
12147
12184
  "ghosty agents set <id> --tool wa:actualizar_identidad=off,teams:actualizar_identidad=on",
12148
12185
  'ghosty agents set minighosty --bag "MiniGhosty" --avatar https://www.ghosty.studio/avatars/minighosty.png',
@@ -12989,6 +13026,10 @@ function normalizeArgs(pos, v) {
12989
13026
  if (v.expires !== void 0) v.vence = v.expires;
12990
13027
  else if (v.vence !== void 0) notes.push(t("`--vence` is now `--expires`.", "`--vence` ahora es `--expires`."));
12991
13028
  }
13029
+ if (cmd === "agents" && (sub === "embed" || sub === "widget") && (pos[2] === "enable" || pos[2] === "disable")) {
13030
+ v[pos[2] === "enable" ? "on" : "off"] = true;
13031
+ pos.splice(2, 1);
13032
+ }
12992
13033
  if (cmd === "channels" && pos[2] === "groups") {
12993
13034
  if (pos[3] === "enable" || pos[3] === "disable") {
12994
13035
  v[pos[3] === "enable" ? "on" : "off"] = true;
@@ -13965,6 +14006,8 @@ ${bold("Agents")}
13965
14006
  agents box <id> The machine serving it: is it on the new image? [--check PATH]\u2026 [--contains PATH=TEXT]\u2026 [--recycle [--reenv] [--force]]
13966
14007
  agents demo enable|disable <id> Turn its public demo link on or off
13967
14008
  agents demo <id> Public demo link /p/<slug>: anyone tries it without an account, "Keep it" clones it to theirs
14009
+ agents embed enable|disable <id> Web widget: a chat bubble on YOUR site (one <script>), only on the domains you list [--domains a.com,*.b.com] [--per-visitor N] [--per-ip N] [--welcome T] [--color #hex] [--rotate]
14010
+ agents embed <id> Its state and the snippet to paste (claude engine only: it isolates each visitor)
13968
14011
  [--slug NAME] [--expires "YYYY-MM-DDTHH:MM"|no] [--turns N] [--per-ip N] [--welcome TEXT] [--chips "a|b|c"] [--starter TEXT] [--sponsor on|off] [--rotate]
13969
14012
 
13970
14013
  ${bold("Configure an agent")}
@@ -14121,6 +14164,8 @@ ${bold("Agentes")}
14121
14164
  agents box <id> La m\xE1quina que lo atiende: \xBFya trae la imagen nueva? [--check RUTA]\u2026 [--contains RUTA=TEXTO]\u2026 [--recycle [--reenv] [--force]]
14122
14165
  agents demo enable|disable <id> Prende o apaga su liga p\xFAblica de demo
14123
14166
  agents demo <id> Liga p\xFAblica de demo /p/<slug>: cualquiera lo prueba sin cuenta y \xABQued\xE1rmelo\xBB lo clona a la suya
14167
+ agents embed enable|disable <id> Widget web: burbuja de chat en TU sitio (un <script>), s\xF3lo en los dominios que pongas [--domains a.com,*.b.com] [--per-visitor N] [--per-ip N] [--welcome T] [--color #hex] [--rotate]
14168
+ agents embed <id> Su estado y el snippet para pegar (s\xF3lo motor claude: a\xEDsla a cada visitante)
14124
14169
  [--slug NOMBRE] [--expires "AAAA-MM-DDTHH:MM"|no] [--turns N] [--per-ip N] [--welcome TEXTO] [--chips "a|b|c"] [--starter TEXTO] [--sponsor on|off] [--rotate]
14125
14170
 
14126
14171
  ${bold("Configurar un agente")}
@@ -14214,7 +14259,7 @@ ${bold("C\xF3digos de salida")} 0 bien \xB7 1 error de la API \xB7 2 uso incorr
14214
14259
  ${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.")}
14215
14260
  ${dim("Documentaci\xF3n: https://www.ghosty.studio/docs/cli")}`;
14216
14261
  var COMMANDS = ["login", "logout", "whoami", "usage", "use", "apply", "plan", "engines", "bags", "spaces", "workspaces", "staff", "audit", "factory", "demos", "sites", "push", "novedades", "completion", "cards", "agents", "files", "skills", "mcp", "dbs", "turns", "try", "chat", "conversations", "schedule", "partner", "me", "channels", "board", "boards", "credentials", "connectors", "browser", "docs", "help"];
14217
- var AGENTS_SUBS = ["ls", "create", "get", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "box"];
14262
+ var AGENTS_SUBS = ["ls", "create", "get", "set", "export", "doctor", "docs", "share", "unshare", "shares", "teams", "rm", "restart", "demo", "embed", "box"];
14218
14263
  function unknown(what, input, known, helpCmd) {
14219
14264
  const s = suggest(input, known);
14220
14265
  return usage(t(`Unknown command: ${what}.`, `Comando desconocido: ${what}.`), s ? t(`Did you mean "${s}"? Run: ${helpCmd}`, `\xBFQuisiste decir "${s}"? Corre: ${helpCmd}`) : t(`Run: ${helpCmd}`, `Corre: ${helpCmd}`));
@@ -14296,6 +14341,9 @@ async function main() {
14296
14341
  turns: { type: "string" },
14297
14342
  vence: { type: "string" },
14298
14343
  "per-ip": { type: "string" },
14344
+ "per-visitor": { type: "string" },
14345
+ domains: { type: "string" },
14346
+ color: { type: "string" },
14299
14347
  welcome: { type: "string" },
14300
14348
  chips: { type: "string" },
14301
14349
  starter: { type: "string" },
@@ -14452,7 +14500,7 @@ async function main() {
14452
14500
  const tokens = splitTokens(pos, v);
14453
14501
  globals.token = tokens.session;
14454
14502
  globals.profile = v.profile;
14455
- if (v.version) return out({ version: "0.50.0" }, () => "0.50.0");
14503
+ if (v.version) return out({ version: "0.51.0" }, () => "0.51.0");
14456
14504
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
14457
14505
  const context = (await readConfig()).workspace;
14458
14506
  if (!explicitToken()?.startsWith("gat_")) {
@@ -14520,6 +14568,7 @@ async function main() {
14520
14568
  if (sub === "docs" || sub === "documents") return agentDocsCmd(a1, a2, pos.slice(4).filter((x) => x !== void 0), v);
14521
14569
  if (sub === "restart") return agentsRestart(a1);
14522
14570
  if (sub === "demo") return agentsDemo(a1, v);
14571
+ if (sub === "embed" || sub === "widget") return agentsEmbed(a1, v);
14523
14572
  if (sub === "box") return agentsBox(a1, v);
14524
14573
  if (sub === "export") return agentsExport(a1, v);
14525
14574
  throw unknown(`agents ${sub}`, sub, AGENTS_SUBS, "ghosty agents --help");
@@ -14617,7 +14666,7 @@ async function main() {
14617
14666
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
14618
14667
  }
14619
14668
  }
14620
- var notice = updateNotice("0.50.0").catch(() => null);
14669
+ var notice = updateNotice("0.51.0").catch(() => null);
14621
14670
  main().then(
14622
14671
  async () => {
14623
14672
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.50.0",
3
+ "version": "0.51.0",
4
4
  "description": "Official Ghosty Studio CLI — configure, test and chat with your agents from the terminal. Built for humans and coding agents.",
5
5
  "type": "module",
6
6
  "bin": {