@ghostystudio/cli 0.46.0 → 0.48.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.
Files changed (3) hide show
  1. package/README.md +9 -0
  2. package/dist/index.js +87 -20
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -103,6 +103,15 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
103
103
 
104
104
  Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
105
105
 
106
+ ### Changes in 0.48.0
107
+
108
+ - `agents teams on <id> <workspace> --factory plan,build,check`: make an agent those Software Factory roles in that workspace (same as «Team» in /factory; each role keeps its name and avatar). `agents teams ls` shows the roles it holds.
109
+
110
+ ### Changes in 0.47.0
111
+
112
+ - `agents set --quote` takes VAT rules for the house `cotizar` tool: `iva-incluido=true` (prices already include VAT), `iva.CATEGORY=16` (VAT for that category), `solo-factura=true` (VAT only when the customer asks for an invoice).
113
+ - New `agents set --catalog products.csv|json`: the house `cotizar` tool's catalog (sku, nombre, precio, unidad, categoria). The category comes from here, not from the model.
114
+
106
115
  ### Changes in 0.46.0
107
116
 
108
117
  - New `staff ls|assign|unassign <staff-email> <client-email>` (Ghosty staff): a staff member assigned to a client account sees and runs its agents (with or without a workspace), documents, databases and boards as themselves — no keys, billing or transfers, every write logged. The client sees «Your Ghosty account manager».
package/dist/index.js CHANGED
@@ -7462,6 +7462,13 @@ var SERVER_MESSAGES = [
7462
7462
  ["@{} ya est\xE1 ocupado por otro agente en este espacio: dale un handle propio", "@{} is already taken by another agent in this workspace: give it its own handle"],
7463
7463
  // — Activar en equipos de Teams (`agents teams`)
7464
7464
  ["@{} ya est\xE1 ocupado en {}", "@{} is already taken in {}"],
7465
+ ["la f\xE1brica no est\xE1 instalada en {}: inst\xE1lala desde /factory en Teams", "the Software Factory isn't installed in {}: install it from /factory in Teams"],
7466
+ ["la f\xE1brica no tiene el rol {}: usa {}", "the Software Factory has no role {}: use {}"],
7467
+ ["faltan los roles: {}", "missing the roles: {}"],
7468
+ ["@eval no existe en {}: act\xEDvalo desde /factory en Teams", "@eval doesn't exist in {}: turn it on from /factory in Teams"],
7469
+ ["@{} no existe en {}: reinstala la f\xE1brica desde /factory en Teams", "@{} doesn't exist in {}: reinstall the Software Factory from /factory in Teams"],
7470
+ ["@{} en {} es de otro agente, no de la f\xE1brica", "@{} in {} belongs to another agent, not to the Software Factory"],
7471
+ ["factory: lista de roles (plan, build, check, eval)", "factory: a list of roles (plan, build, check, eval)"],
7465
7472
  ["@{} est\xE1 reservado", "@{} is reserved"],
7466
7473
  ["los @handle {} a {}5 ya est\xE1n ocupados en {}", "handles @{} to @{}5 are already taken in {}"],
7467
7474
  ["no administras el equipo {}", "you don't administer the workspace {}"],
@@ -8422,7 +8429,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
8422
8429
  const req = httpsRequest(`${base}${path}`, {
8423
8430
  method: "POST",
8424
8431
  timeout: timeoutMs,
8425
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.46.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8432
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.48.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8426
8433
  }, (res) => {
8427
8434
  let buf = "";
8428
8435
  res.on("data", (c) => buf += c);
@@ -8464,7 +8471,7 @@ async function request(path, opts = {}, retried = false) {
8464
8471
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
8465
8472
  headers: {
8466
8473
  authorization: `Bearer ${token}`,
8467
- "user-agent": `ghosty-cli/${"0.46.0"}`,
8474
+ "user-agent": `ghosty-cli/${"0.48.0"}`,
8468
8475
  "accept-language": lang(),
8469
8476
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
8470
8477
  ...opts.headers
@@ -8764,6 +8771,36 @@ async function agentsGet(id, fields, promptOut) {
8764
8771
  const q = fields ? `?fields=${enc2(fields)}` : "?full=1";
8765
8772
  out(await api(agentPath(id, q)));
8766
8773
  }
8774
+ function parseCsv(text) {
8775
+ const rows = [];
8776
+ let row = [], cell = "", q = false;
8777
+ for (let i = 0; i < text.length; i++) {
8778
+ const c = text[i];
8779
+ if (q) {
8780
+ if (c === '"' && text[i + 1] === '"') {
8781
+ cell += '"';
8782
+ i++;
8783
+ } else if (c === '"') q = false;
8784
+ else cell += c;
8785
+ } else if (c === '"') q = true;
8786
+ else if (c === ",") {
8787
+ row.push(cell);
8788
+ cell = "";
8789
+ } else if (c === "\n" || c === "\r") {
8790
+ if (c === "\r" && text[i + 1] === "\n") i++;
8791
+ row.push(cell);
8792
+ cell = "";
8793
+ if (row.some((x) => x.trim())) rows.push(row);
8794
+ row = [];
8795
+ } else cell += c;
8796
+ }
8797
+ row.push(cell);
8798
+ if (row.some((x) => x.trim())) rows.push(row);
8799
+ const [head, ...body] = rows;
8800
+ if (!head) return [];
8801
+ const keys = head.map((h) => h.trim().toLowerCase());
8802
+ return body.map((r) => Object.fromEntries(keys.map((k, i) => [k, k === "precio" ? Number((r[i] ?? "").replace(/[$,\s]/g, "")) : (r[i] ?? "").trim()])));
8803
+ }
8767
8804
  async function agentsSet(id, v) {
8768
8805
  id = need(id, "agent id", "ghosty agents set <agent-id> --prompt-file PROMPT.md");
8769
8806
  const done = [];
@@ -8864,19 +8901,32 @@ ${dim(t("Dry run: nothing changed.", "Simulacro: no se cambi\xF3 nada."))}`);
8864
8901
  body.autoStage = v["auto-stage"] === "on";
8865
8902
  }
8866
8903
  if (v.quote) {
8867
- const alias = { iva: "ivaPct", vigencia: "vigenciaDias", prefix: "folioPrefijo", prefijo: "folioPrefijo", currency: "moneda", company: "empresa", phone: "telefono", email: "correo", address: "direccion", notes: "notas" };
8904
+ const alias = { iva: "ivaPct", vigencia: "vigenciaDias", prefix: "folioPrefijo", prefijo: "folioPrefijo", currency: "moneda", company: "empresa", phone: "telefono", email: "correo", address: "direccion", notes: "notas", "iva-incluido": "ivaIncluido", "solo-factura": "ivaSoloConFactura" };
8868
8905
  const cot = {};
8869
- for (const part of v.quote.split(/,(?=\s*[a-zA-Z]+=)/)) {
8870
- const m = /^\s*([a-zA-Z]+)=(.*)$/.exec(part);
8906
+ let cats = null;
8907
+ for (const part of v.quote.split(/,(?=\s*[a-zA-Z-]+(?:\.[^=,]+)?=)/)) {
8908
+ const m = /^\s*([a-zA-Z-]+)(?:\.([^=]+))?=(.*)$/.exec(part);
8871
8909
  if (!m) throw usage(t(`Bad --quote: ${part}.`, `--quote inv\xE1lido: ${part}.`), "--quote iva=0,prefix=SFI,vigencia=15");
8872
- const key = alias[m[1]] ?? m[1];
8873
- const val = m[2].trim().replace(/^"(.*)"$/, "$1");
8874
- cot[key] = key === "ivaPct" || key === "vigenciaDias" ? Number(val) : val;
8910
+ const [, rawKey, category, rawVal] = m;
8911
+ const val = rawVal.trim().replace(/^"(.*)"$/, "$1");
8912
+ if (rawKey.toLowerCase() === "iva" && category) {
8913
+ if (!cats) cats = { ...(await api(agentPath(id, "?fields=cotizacion"))).cotizacion?.ivaPorCategoria ?? {} };
8914
+ if (val === "") delete cats[category];
8915
+ else cats[category] = Number(val);
8916
+ continue;
8917
+ }
8918
+ const key = alias[rawKey] ?? rawKey;
8919
+ cot[key] = key === "ivaPct" || key === "vigenciaDias" ? Number(val) : key === "ivaIncluido" || key === "ivaSoloConFactura" ? /^(true|on|yes|si|sí|1)$/i.test(val) : val;
8875
8920
  }
8921
+ if (cats) cot.ivaPorCategoria = cats;
8876
8922
  body.cotizacion = cot;
8877
8923
  }
8924
+ if (v.catalog) {
8925
+ const raw = await readFile3(resolve(v.catalog), "utf8");
8926
+ body.catalogo = v.catalog.toLowerCase().endsWith(".json") ? JSON.parse(raw) : parseCsv(raw);
8927
+ }
8878
8928
  if (!Object.keys(body).length && done.length) return out({ id, updated: done }, () => `${lavender("\u2713")} ${t("Updated", "Actualizado")}: ${done.join(" \xB7 ")}`);
8879
- if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), t("Use", "Usa") + " --name, --engine, --model, --prompt, --prompt-file, --env, --unset-env, --channels, --toolsets, --tool, --connect, --disconnect, --voice, --voice-replies, --auto-stage, --quote, --bag " + t("or", "o") + " --avatar.");
8929
+ if (!Object.keys(body).length) throw usage(t("Nothing to change.", "Nada que cambiar."), t("Use", "Usa") + " --name, --engine, --model, --prompt, --prompt-file, --env, --unset-env, --channels, --toolsets, --tool, --connect, --disconnect, --voice, --voice-replies, --auto-stage, --quote, --catalog, --bag " + t("or", "o") + " --avatar.");
8880
8930
  const r = await api(agentPath(id), { method: "PATCH", body });
8881
8931
  out(r, () => `${lavender("\u2713")} ${t("Updated", "Actualizado")}: ${[...Object.keys(body), ...done].join(", ")}.`);
8882
8932
  }
@@ -8922,7 +8972,7 @@ ${rows.length ? table(rows, ["email", "role", "accepted"]) : dim(t("Not shared w
8922
8972
  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})`)}.`);
8923
8973
  }
8924
8974
  async function agentsTeams(sub, id, ws, v) {
8925
- 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]";
8975
+ const ex = "ghosty agents teams ls <agent-id> \xB7 on <agent-id> <workspace> [--handle x | --factory plan,build,check] \xB7 off <agent-id> <workspace> \xB7 rm <agent-id> <workspace> [--yes]";
8926
8976
  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);
8927
8977
  id = need(id, "agent id", ex);
8928
8978
  if (sub === "ls") {
@@ -8932,7 +8982,7 @@ async function agentsTeams(sub, id, ws, v) {
8932
8982
  const state = x.state ?? (x.active ? "on" : "off");
8933
8983
  return {
8934
8984
  workspace: x.slug,
8935
- handle: state === "off" ? dim(`(@${x.suggested})`) : `@${x.handle}`,
8985
+ handle: state === "off" ? dim(`(@${x.suggested})`) : `@${x.handle}` + (x.roles?.filter((h) => h !== x.handle).length ? dim(` + ${x.roles.filter((h) => h !== x.handle).map((h) => `@${h}`).join(" ")}`) : ""),
8936
8986
  state: !x.confirmed ? t("unconfirmed", "sin confirmar") : label[state] + (x.editable === false ? dim(t(" \xB7 not yours to change", " \xB7 no lo administras")) : "")
8937
8987
  };
8938
8988
  });
@@ -8949,6 +8999,13 @@ async function agentsTeams(sub, id, ws, v) {
8949
8999
  const r2 = await api(agentPath(id, `/teams?workspace=${encodeURIComponent(workspace)}`), { method: "DELETE", body: { workspace } });
8950
9000
  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}.`)}`);
8951
9001
  }
9002
+ if (v.factory !== void 0) {
9003
+ if (v.handle) throw usage(t("Use --handle or --factory, not both.", "Usa --handle o --factory, no los dos."), ex);
9004
+ const roles = v.factory.split(",").map((x) => x.trim().replace(/^@/, "")).filter(Boolean);
9005
+ if (!roles.length) throw usage(t("--factory needs roles: plan,build,check (or eval).", "--factory necesita roles: plan,build,check (o eval)."), ex);
9006
+ const r2 = await api(agentPath(id, "/teams"), { method: "POST", body: { workspace, factory: roles } });
9007
+ return out(r2, () => `${lavender("\u2713")} ${t(`In ${workspace} it now is`, `En ${workspace} ahora es`)} ${r2.roles.map((x) => `@${x.handle}`).join(", ")}${dim(t(` (before: ${r2.roles.map((x) => x.previous ?? "\u2014").join(", ")})`, ` (antes: ${r2.roles.map((x) => x.previous ?? "\u2014").join(", ")})`))}. ${t("The next turn of each role runs on it.", "El siguiente turno de cada rol ya corre en \xE9l.")}`);
9008
+ }
8952
9009
  const r = await api(agentPath(id, "/teams"), { method: "POST", body: { workspace, ...v.handle ? { handle: v.handle } : {} } });
8953
9010
  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}.`)}`);
8954
9011
  }
@@ -9738,7 +9795,7 @@ async function call(path, v, init = {}) {
9738
9795
  "x-ghosty-ts": ts,
9739
9796
  "x-ghosty-sig": sig,
9740
9797
  "content-type": "application/json",
9741
- "user-agent": `ghosty-cli/${"0.46.0"}`
9798
+ "user-agent": `ghosty-cli/${"0.48.0"}`
9742
9799
  },
9743
9800
  body: method === "GET" ? void 0 : raw
9744
9801
  });
@@ -11225,7 +11282,8 @@ var HELPS_ES = {
11225
11282
  ["--voice E:ID", "set: voz de las notas de voz: elevenlabs:<voiceId> o kokoro:em_santa|em_alex|ef_dora"],
11226
11283
  ["--voice-replies M", "set: auto = contesta con nota de voz cuando el cliente manda o pide audio; off = siempre texto"],
11227
11284
  ["--auto-stage on|off", "set: mueve solo las tarjetas del tablero tras cada turno del cliente (una llamada extra al modelo por turno)"],
11228
- ["--quote k=v,\u2026", "set: config de la tool de casa `cotizar` \u2014 iva (0-100), vigencia (d\xEDas), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Vac\xEDo lo borra (rfc=). El contador de folio no se toca"],
11285
+ ["--quote k=v,\u2026", "set: config de la tool de casa `cotizar` \u2014 iva (0-100), iva-incluido=true (los precios del cat\xE1logo ya traen IVA), iva.CATEGORIA=16 (IVA de esa categor\xEDa del cat\xE1logo; iva.CATEGORIA= la quita), solo-factura=true (IVA s\xF3lo si el cliente pide factura), vigencia (d\xEDas), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Vac\xEDo lo borra (rfc=). El contador de folio no se toca"],
11286
+ ["--catalog FILE", "set: el cat\xE1logo de la tool de casa `cotizar` desde un CSV (sku,nombre,precio[,unidad,categoria,descripcion]) o una lista JSON; reemplaza al anterior. Su `categoria` decide las reglas de IVA"],
11229
11287
  ["--verbose", "doctor: lista tambi\xE9n las revisiones que pasaron"],
11230
11288
  ["--user EMAIL", "doctor (staff de Ghosty): los agentes de esa persona \u2014 doctor, \xFAltimos turnos (estado, segundos, error y \xABfetched\xBB: si su app pidi\xF3 el hilo despu\xE9s de que termin\xF3 el turno), plan/bolsa y cajas (marca duplicadas); queda en bit\xE1cora"],
11231
11289
  ["--turns N", "doctor --user: cu\xE1ntos turnos recientes por agente (default 8, m\xE1x. 50)"],
@@ -11236,6 +11294,7 @@ var HELPS_ES = {
11236
11294
  ["--note TEXT", "docs replace/restore: por qu\xE9 cambi\xF3 (sale en docs history)"],
11237
11295
  ["--role R", "share: editor (lo configura y lo usa) o admin (adem\xE1s lo comparte); repetirlo sobre un correo ya compartido cambia el rol"],
11238
11296
  ["--handle NAME", "teams on: su @handle en ese equipo (default: sacado de su nombre, con sufijo si est\xE1 ocupado; @ghosty est\xE1 reservado). Sobre un equipo donde ya est\xE1, le cambia el handle"],
11297
+ ["--factory ROLES", "teams on: le pasa esos roles de la Software Factory del equipo (plan, build, check, eval; separados por comas) \u2014 lo mismo que \xABEquipo\xBB en /factory. Cada rol conserva su nombre y avatar; su siguiente turno ya corre en \xE9l. La f\xE1brica tiene que estar instalada ah\xED"],
11239
11298
  ["--yes", "rm: se salta la confirmaci\xF3n (obligatorio sin terminal)"],
11240
11299
  ["--slug NAME", "demo: nombre de la liga; se le agrega un c\xF3digo de 6 caracteres (/p/NAME-CODE)"],
11241
11300
  ["--expires DATE|no", 'demo: caducidad fija en la hora de tu m\xE1quina ("2026-10-15T20:00"); no = nunca'],
@@ -11640,6 +11699,7 @@ var HELPS = {
11640
11699
  "ghosty agents shares <agent-id>",
11641
11700
  "ghosty agents teams ls <agent-id> # Teams workspaces you administer: where it answers, is paused, and with which @handle",
11642
11701
  "ghosty agents teams on <agent-id> <workspace> [--handle NAME] # turn it on there (or change its @handle)",
11702
+ "ghosty agents teams on <agent-id> <workspace> --factory plan,build,check # make it the workspace's Software Factory roles",
11643
11703
  "ghosty agents teams off <agent-id> <workspace> # pause it there; it keeps its @handle",
11644
11704
  "ghosty agents teams rm <agent-id> <workspace> [--yes] # remove it from there; the agent stays",
11645
11705
  "ghosty agents restart <agent-id>",
@@ -11664,7 +11724,8 @@ var HELPS = {
11664
11724
  ["--voice E:ID", "set: voice for voice notes: elevenlabs:<voiceId> or kokoro:em_santa|em_alex|ef_dora"],
11665
11725
  ["--voice-replies M", "set: auto = answer with a voice note when the customer sends or asks for audio; off = always text"],
11666
11726
  ["--auto-stage on|off", "set: move board cards by itself after each customer turn (one extra model call per turn)"],
11667
- ["--quote k=v,\u2026", "set: config of the house `cotizar` tool \u2014 iva (0-100), vigencia (days), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Empty value clears it (rfc=). The folio counter is never touched"],
11727
+ ["--quote k=v,\u2026", "set: config of the house `cotizar` tool \u2014 iva (0-100), iva-incluido=true (catalog prices already include VAT), iva.CATEGORY=16 (VAT for that catalog category; iva.CATEGORY= removes it), solo-factura=true (VAT only when the customer asks for an invoice), vigencia (days), prefix (folio), moneda, empresa, rfc, telefono, correo, direccion, notas, color. Empty value clears it (rfc=). The folio counter is never touched"],
11728
+ ["--catalog FILE", "set: the house `cotizar` tool's catalog from a CSV (sku,nombre,precio[,unidad,categoria,descripcion]) or JSON list; replaces the previous one. Its `categoria` drives the VAT rules"],
11668
11729
  ["--verbose", "doctor: also list the checks that passed"],
11669
11730
  ["--user EMAIL", "doctor (Ghosty staff): that person's agents \u2014 doctor, latest turns (state, seconds, error, and \xABfetched\xBB: whether their app asked for the thread after the turn ended), plan/bag and boxes (duplicates flagged); logged"],
11670
11731
  ["--turns N", "doctor --user: how many recent turns per agent (default 8, max 50)"],
@@ -11675,6 +11736,7 @@ var HELPS = {
11675
11736
  ["--note TEXT", "docs replace/restore: why it changed (shown in docs history)"],
11676
11737
  ["--role R", "share: editor (configures and uses it) or admin (also shares it); again on a shared email changes the role"],
11677
11738
  ["--handle NAME", "teams on: its @handle in that workspace (default: from its name, with a suffix if taken; @ghosty is reserved). On an active workspace it changes the handle"],
11739
+ ["--factory ROLES", "teams on: give it those Software Factory roles in that workspace (plan, build, check, eval; comma-separated) \u2014 the same as \xABTeam\xBB in /factory. Keeps each role's name and avatar; the next turn of each role runs on it. The factory must be installed there"],
11678
11740
  ["--yes", "rm: skip the confirmation (required without a terminal)"],
11679
11741
  ["--slug NAME", "demo: link name; a 6-char code is appended (/p/NAME-CODE)"],
11680
11742
  ["--expires DATE|no", `demo: fixed expiry in your machine's time ("2026-10-15T20:00"); no = never`],
@@ -11712,6 +11774,7 @@ var HELPS = {
11712
11774
  "ghosty agents set <id> --toolsets +crm",
11713
11775
  "ghosty agents share <id> ana@empresa.com --role admin",
11714
11776
  "ghosty agents teams on <id> abogados --handle licenciado",
11777
+ "ghosty agents teams on <id> mercadito-verde --factory plan,build,check",
11715
11778
  "ghosty agents get <id> --prompt-out PROMPT.md",
11716
11779
  "ghosty agents get <id> --fields toolsets,connectors # what it really has: effective toolsets, connectors connected + granted",
11717
11780
  "ghosty agents create --name tania-mkt --like <pia-id> --board new --no-notify --dry-run",
@@ -13370,7 +13433,8 @@ ${bold("Agents")}
13370
13433
  [--connect google-drive,\u2026] [--disconnect \u2026] give/remove access to your connectors
13371
13434
  [--channels wa=on,teams=off] turn channels on/off (wa = personal WhatsApp)
13372
13435
  [--voice elevenlabs:ID | kokoro:em_santa] [--voice-replies auto|off] [--auto-stage on|off]
13373
- [--quote iva=0,prefix=SFI,vigencia=15] house cotizar tool config (issuer, VAT, folio)
13436
+ [--quote iva=16,iva-incluido=true,iva.GRANEL=16,solo-factura=true,prefix=SFI] house cotizar tool config (issuer, VAT rules, folio)
13437
+ [--catalog productos.csv|json] its catalog: sku,nombre,precio[,unidad,categoria]
13374
13438
  [--toolsets crm,sales | +crm,-sales] gs tool groups it gets
13375
13439
  [--prompt-base AGENT|none --prompt-overlay FILE [--dry-run]] prompt = another agent's + edits, kept in sync
13376
13440
  [--tool wa:tool=off,\u2026] [--bag NAME|none] [--avatar URL|FILE] a tool per channel \xB7 its token bag (staff) \xB7 its face in Teams
@@ -13383,7 +13447,7 @@ ${bold("Agents")}
13383
13447
  agents docs replace <id> <doc> New version (keeps name and access) --url URL | --file PATH [--note]
13384
13448
  agents docs history|restore <id> <doc> [n] Its versions; restore n as a new version
13385
13449
  agents share|unshare <id> <email> Share it without handing it over [--role editor|admin] \xB7 agents shares <id> lists them
13386
- agents teams ls|on|off|rm <id> [ws] Which Teams workspaces it answers in, and its @handle there [--handle x]
13450
+ agents teams ls|on|off|rm <id> [ws] Which Teams workspaces it answers in, and its @handle there [--handle x] [--factory plan,build,check: its Software Factory roles]
13387
13451
  agents rm <id> Delete an agent (owner only; asks you to type its name, or --yes) [--from-workspace: turn it off in Teams first]
13388
13452
  agents restart <id> Restart an ACP agent (needsRestart) so it loads new skills
13389
13453
  agents box <id> The machine serving it: is it on the new image? [--check PATH]\u2026 [--contains PATH=TEXT]\u2026 [--recycle [--reenv] [--force]]
@@ -13515,7 +13579,8 @@ ${bold("Agentes")}
13515
13579
  [--connect google-drive,\u2026] [--disconnect \u2026] dale o qu\xEDtale acceso a tus conectores
13516
13580
  [--channels wa=on,teams=off] prende/apaga canales (wa = WhatsApp personal)
13517
13581
  [--voice elevenlabs:ID | kokoro:em_santa] [--voice-replies auto|off] [--auto-stage on|off]
13518
- [--quote iva=0,prefix=SFI,vigencia=15] config de la tool de casa cotizar (emisor, IVA, folio)
13582
+ [--quote iva=16,iva-incluido=true,iva.GRANEL=16,solo-factura=true,prefix=SFI] config de la tool de casa cotizar (emisor, reglas de IVA, folio)
13583
+ [--catalog productos.csv|json] su cat\xE1logo: sku,nombre,precio[,unidad,categoria]
13519
13584
  [--toolsets crm,sales | +crm,-sales] grupos de tools de gs que recibe
13520
13585
  [--prompt-base AGENTE|none --prompt-overlay ARCHIVO [--dry-run]] prompt = el de otro agente + ediciones, sincronizado
13521
13586
  [--tool wa:tool=off,\u2026] [--bag NOMBRE|none] [--avatar URL|ARCHIVO] una tool por canal \xB7 su bolsa de tokens (staff) \xB7 su cara en Teams
@@ -13528,7 +13593,7 @@ ${bold("Agentes")}
13528
13593
  agents docs replace <id> <doc> Versi\xF3n nueva (conserva nombre y accesos) --url URL | --file RUTA [--note]
13529
13594
  agents docs history|restore <id> <doc> [n] Sus versiones; restaura la n como versi\xF3n nueva
13530
13595
  agents share|unshare <id> <correo> Comp\xE1rtelo sin cederlo [--role editor|admin] \xB7 agents shares <id> los lista
13531
- agents teams ls|on|off|rm <id> [equipo] En qu\xE9 equipos de Teams contesta y con qu\xE9 @handle [--handle x]
13596
+ agents teams ls|on|off|rm <id> [equipo] En qu\xE9 equipos de Teams contesta y con qu\xE9 @handle [--handle x] [--factory plan,build,check: sus roles de la Software Factory]
13532
13597
  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]
13533
13598
  agents restart <id> Reinicia un agente ACP (needsRestart) para que cargue skills nuevas
13534
13599
  agents box <id> La m\xE1quina que lo atiende: \xBFya trae la imagen nueva? [--check RUTA]\u2026 [--contains RUTA=TEXTO]\u2026 [--recycle [--reenv] [--force]]
@@ -13762,6 +13827,7 @@ async function main() {
13762
13827
  days: { type: "string" },
13763
13828
  voice: { type: "string" },
13764
13829
  quote: { type: "string" },
13830
+ catalog: { type: "string" },
13765
13831
  "voice-replies": { type: "string" },
13766
13832
  "auto-stage": { type: "string" },
13767
13833
  "from-env": { type: "string" },
@@ -13777,6 +13843,7 @@ async function main() {
13777
13843
  recycle: { type: "boolean" },
13778
13844
  role: { type: "string" },
13779
13845
  handle: { type: "string" },
13846
+ factory: { type: "string" },
13780
13847
  wake: { type: "string" },
13781
13848
  text: { type: "string" },
13782
13849
  sender: { type: "string" },
@@ -13850,7 +13917,7 @@ async function main() {
13850
13917
  const tokens = splitTokens(pos, v);
13851
13918
  globals.token = tokens.session;
13852
13919
  globals.profile = v.profile;
13853
- if (v.version) return out({ version: "0.46.0" }, () => "0.46.0");
13920
+ if (v.version) return out({ version: "0.48.0" }, () => "0.48.0");
13854
13921
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
13855
13922
  const context = (await readConfig()).workspace;
13856
13923
  if (!explicitToken()?.startsWith("gat_")) {
@@ -14010,7 +14077,7 @@ async function main() {
14010
14077
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
14011
14078
  }
14012
14079
  }
14013
- var notice = updateNotice("0.46.0").catch(() => null);
14080
+ var notice = updateNotice("0.48.0").catch(() => null);
14014
14081
  main().then(
14015
14082
  async () => {
14016
14083
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.46.0",
3
+ "version": "0.48.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": {