@ghostystudio/cli 0.54.0 → 0.55.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 +7 -1
  2. package/dist/index.js +77 -18
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -109,6 +109,12 @@ Every command has its own help with examples: `ghosty <command> --help` or `ghos
109
109
 
110
110
  Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
111
111
 
112
+ ### Changes in 0.55.0
113
+
114
+ - `factory runs show <run> --timing`: where a run's time and money went — each turn of each role (critic, @plan, @build, @check) with minutes, minutes in tools, model and USD; the clock split into working, waiting for a person and the rest (CI, queues); and the commands that took 60 s or more.
115
+ - `factory runs stats [--since 30d] [--repo owner/repo]`: runs, % merged, median minutes to PR and to merge, @check→@build loops, red CI per run, and cost per run and per merged PR.
116
+ - `factory runs ls` shows each run's time and cost.
117
+
112
118
  ### Changes in 0.54.0
113
119
 
114
120
  - `agents embed <id> --copy '{json}'|none` and `--copy-file texts.json`: the phrases the web widget shows while the agent works (`waking`, `connecting`, `thinking` — 1–8 that rotate —, `stillWorking`, `cantStart`, `interrupted`, `retryLabel`, plain text ≤ 80 chars) and whether it shows the duration and the Copy button (`showDuration`, `showCopyButton`). Patch per key; `null` = Ghosty's phrase. `agents embed <id> theme` exports `copy` too, and `--out` bakes it into the component.
@@ -134,7 +140,7 @@ Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
134
140
  - `channels whatsapp integrations` shows who answered each number last; `--orphans` and `channels messenger ls [--orphans]` list numbers/pages nobody answers today that had turns.
135
141
  - `agents set --prompt-patch overlay.json` / `--prompt-append FILE [--dry-run]`: change one piece of the prompt on the server's current copy (dry run prints the diff).
136
142
  - `audit ls [--workspace] [--agent] [--actor] [--action] [--since]`: the audit log. The agent page's Save and channel changes are logged now.
137
- - `factory runs ls|show|rename` (a workspace's Software Factory runs) and `agents ls --handle build`.
143
+ - `factory runs ls|show|rename` (a workspace's Software Factory runs) and `agents ls --handle build`. Since 0.55: `show --timing` and `stats`.
138
144
 
139
145
  ### Changes in 0.49.0
140
146
 
package/dist/index.js CHANGED
@@ -8468,7 +8468,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
8468
8468
  const req = httpsRequest(`${base}${path}`, {
8469
8469
  method: "POST",
8470
8470
  timeout: timeoutMs,
8471
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.54.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8471
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.55.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
8472
8472
  }, (res) => {
8473
8473
  let buf = "";
8474
8474
  res.on("data", (c) => buf += c);
@@ -8510,7 +8510,7 @@ async function request(path, opts = {}, retried = false) {
8510
8510
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
8511
8511
  headers: {
8512
8512
  authorization: `Bearer ${token}`,
8513
- "user-agent": `ghosty-cli/${"0.54.0"}`,
8513
+ "user-agent": `ghosty-cli/${"0.55.0"}`,
8514
8514
  "accept-language": lang(),
8515
8515
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
8516
8516
  ...opts.headers
@@ -10404,7 +10404,7 @@ async function call(path, v, init = {}) {
10404
10404
  "x-ghosty-ts": ts,
10405
10405
  "x-ghosty-sig": sig,
10406
10406
  "content-type": "application/json",
10407
- "user-agent": `ghosty-cli/${"0.54.0"}`
10407
+ "user-agent": `ghosty-cli/${"0.55.0"}`
10408
10408
  },
10409
10409
  body: method === "GET" ? void 0 : raw
10410
10410
  });
@@ -12492,7 +12492,7 @@ var HELPS_ES = {
12492
12492
  ]
12493
12493
  },
12494
12494
  factory: {
12495
- summary: "Los pedidos de la Software Factory de un espacio (viven en su Teams): listarlos, ver uno (plan vigente, PR, preview, \xFAltimos eventos, qu\xE9 rol trabaja) y corregir el t\xEDtulo de un pedido.",
12495
+ summary: "Los pedidos de la Software Factory de un espacio (viven en su Teams): listarlos con tiempo y costo, ver uno (plan vigente, PR, preview, \xFAltimos eventos, qu\xE9 rol trabaja), ver en qu\xE9 se fue su tiempo y su dinero, los totales del espacio y corregir el t\xEDtulo de un pedido.",
12496
12496
  replace: [['"Title"', '"T\xEDtulo"']],
12497
12497
  flags: [
12498
12498
  ["--workspace SLUG", "el espacio (default: el de ghosty use)"],
@@ -12500,12 +12500,17 @@ var HELPS_ES = {
12500
12500
  ["--status S", "ls: s\xF3lo esa etapa (planning, building, checking, pr_review, merged\u2026)"],
12501
12501
  ["--limit N", "ls: cu\xE1ntos (default 30)"],
12502
12502
  ["--full", "show: imprime el plan vigente"],
12503
+ ["--timing", "show: cada turno de cada rol (cr\xEDtico, @plan, @build, @check) con minutos, minutos en tools, modelo y USD; el reloj del pedido partido en trabajando, esperando a una persona (plan o PR por aprobar) y lo dem\xE1s (CI, colas); y los comandos de 60 s o m\xE1s"],
12504
+ ["--since 30d", "stats: cu\xE1nto hacia atr\xE1s (d\xEDas, default 30)"],
12505
+ ["--repo OWNER/REPO", "stats: s\xF3lo ese repo (due\xF1o/repo)"],
12503
12506
  ["-n, --dry-run", "rename: ense\xF1a el cambio, no cambia nada"],
12504
12507
  ["--yes", "rename: se salta la confirmaci\xF3n (obligatorio sin terminal)"]
12505
12508
  ],
12506
12509
  notes: [
12507
12510
  "Leer pide ser miembro del espacio; renombrar, ser due\xF1o, admin o staff de Ghosty, y queda en bit\xE1cora (factory.run_rename). La tarjeta del room toma el t\xEDtulo nuevo en su siguiente refresco.",
12508
- "Qui\xE9n es @plan o @build: ghosty agents ls --handle plan --workspace SLUG."
12511
+ "Qui\xE9n es @plan o @build: ghosty agents ls --handle plan --workspace SLUG.",
12512
+ "stats: pedidos, % mezclados, mediana de minutos hasta el PR y hasta el merge, vueltas @check\u2192@build y CI rojo por pedido, y costo por pedido y por PR mezclado. El costo incluye el primer turno de @plan en el hilo, antes de que naciera el pedido.",
12513
+ "--timing lee la transcripci\xF3n de cada rol: los motores sin una (ACP) salen con minutos y costo, pero sin comandos."
12509
12514
  ]
12510
12515
  }
12511
12516
  };
@@ -13239,10 +13244,12 @@ HELPS.audit = {
13239
13244
  learn: `${REF}#bitacora`
13240
13245
  };
13241
13246
  HELPS.factory = {
13242
- summary: "A workspace's Software Factory runs (they live in its Teams): list them, see one (current plan, PR, preview, latest events, which role is working) and fix a run's title.",
13247
+ summary: "A workspace's Software Factory runs (they live in its Teams): list them with time and cost, see one (current plan, PR, preview, latest events, which role is working), see where its time and money went, totals for the workspace, and fix a run's title.",
13243
13248
  usage: [
13244
13249
  "ghosty factory runs ls [--workspace SLUG] [--room R] [--status S] [--limit 30]",
13245
13250
  "ghosty factory runs show <run> [--workspace SLUG] [--full]",
13251
+ "ghosty factory runs show <run> --timing [--workspace SLUG]",
13252
+ "ghosty factory runs stats [--since 30d] [--repo OWNER/REPO] [--workspace SLUG]",
13246
13253
  'ghosty factory runs rename <run> "Title" [--workspace SLUG] [--dry-run] [--yes]'
13247
13254
  ],
13248
13255
  flags: [
@@ -13251,11 +13258,14 @@ HELPS.factory = {
13251
13258
  ["--status S", "ls: only that stage (planning, building, checking, pr_review, merged\u2026)"],
13252
13259
  ["--limit N", "ls: how many (default 30)"],
13253
13260
  ["--full", "show: print the current plan"],
13261
+ ["--timing", "show: each turn of each role (critic, @plan, @build, @check) with minutes, minutes in tools, model and USD; the run's clock split into working, waiting for a person (plan or PR to approve) and the rest (CI, queues); and the commands that took 60 s or more"],
13262
+ ["--since 30d", "stats: how far back (days, default 30)"],
13263
+ ["--repo OWNER/REPO", "stats: only that repo"],
13254
13264
  ["-n, --dry-run", "rename: show the change, change nothing"],
13255
13265
  ["--yes", "rename: skip the confirmation (required without a terminal)"]
13256
13266
  ],
13257
- examples: ["ghosty factory runs ls --workspace business --room mailmask", "ghosty factory runs show 15 --workspace business", 'ghosty factory runs rename 15 "Docs del CLI al d\xEDa" --workspace business --dry-run'],
13258
- notes: ["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."],
13267
+ examples: ["ghosty factory runs ls --workspace business --room mailmask", "ghosty factory runs show 15 --workspace business", "ghosty factory runs show 31 --timing --workspace mercadito-verde", "ghosty factory runs stats --since 7d --workspace mercadito-verde", 'ghosty factory runs rename 15 "Docs del CLI al d\xEDa" --workspace business --dry-run'],
13268
+ notes: ["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."],
13259
13269
  learn: `${REF}#fabrica`
13260
13270
  };
13261
13271
  function helpText(cmd) {
@@ -13613,11 +13623,11 @@ async function planCmd(sub, slug, v, context) {
13613
13623
  if (!slug) throw usage(t("Missing workspace.", "Falta el espacio."), "ghosty plan apply <workspace> [--dry-run] (or ghosty use <workspace>)");
13614
13624
  const path = `/api/v2/workspaces/${encodeURIComponent(slug)}/plan/apply`;
13615
13625
  const plan = await api(path, { method: "POST", body: { dryRun: true } });
13616
- const money = (n) => `$${n.toLocaleString("es-MX")} MXN`;
13626
+ const money2 = (n) => `$${n.toLocaleString("es-MX")} MXN`;
13617
13627
  const text = [
13618
13628
  `${bold(plan.workspace)} ${dim(plan.scheduledFor ? t(`scheduled for ${plan.scheduledFor.slice(0, 10)}`, `programado para el ${plan.scheduledFor.slice(0, 10)}`) : "")}`,
13619
13629
  ...plan.changes.map((c) => ` ~ ${c.label}: ${String(c.from)} \u2192 ${String(c.to)}`),
13620
- ` ${t("monthly", "al mes")}: ${money(plan.monthlyTotal.from)} \u2192 ${money(plan.monthlyTotal.to)}`
13630
+ ` ${t("monthly", "al mes")}: ${money2(plan.monthlyTotal.from)} \u2192 ${money2(plan.monthlyTotal.to)}`
13621
13631
  ].join("\n");
13622
13632
  if (v["dry-run"]) return out(plan, () => `${text}
13623
13633
  ${dim(t("Dry run: nothing applied.", "Simulaci\xF3n: no se aplic\xF3 nada."))}`);
@@ -14110,21 +14120,68 @@ ${dim(t("Times in UTC. --full for the whole detail; --json for everything.", "Ho
14110
14120
 
14111
14121
  // src/commands/factory.ts
14112
14122
  var enc12 = encodeURIComponent;
14123
+ var money = (n) => n === null || n === void 0 ? "\u2014" : `$${n.toFixed(2)}`;
14124
+ var mins = (n) => n === null || n === void 0 ? "\u2014" : n >= 120 ? `${(n / 60).toFixed(1)} h` : `${n} min`;
14125
+ var hhmm = (iso) => new Date(iso).toLocaleTimeString("es-MX", { hour: "2-digit", minute: "2-digit", hour12: false });
14113
14126
  var short2 = (s2) => (s2 ?? "").slice(0, 16).replace("T", " ");
14114
14127
  async function factoryCmd(sub, verb, ref, title, v, context) {
14115
- if (sub !== "runs") throw usage(t(`Unknown factory subcommand: ${sub ?? "(none)"}.`, `Subcomando de factory desconocido: ${sub ?? "(ninguno)"}.`), "ghosty factory runs ls|show|rename \u2026");
14128
+ if (sub !== "runs") throw usage(t(`Unknown factory subcommand: ${sub ?? "(none)"}.`, `Subcomando de factory desconocido: ${sub ?? "(ninguno)"}.`), "ghosty factory runs ls|show|stats|rename \u2026");
14116
14129
  const ws = v.workspace ?? context;
14117
14130
  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)."));
14118
14131
  const base = `/api/v2/workspaces/${enc12(ws)}/factory/runs`;
14119
14132
  if (!verb || verb === "ls" || verb === "list") {
14120
14133
  const qs = new URLSearchParams({ ...v.room ? { room: v.room } : {}, ...v.status ? { status: v.status } : {}, ...v.limit ? { limit: v.limit } : {} });
14121
14134
  const r = await api(`${base}?${qs}`);
14122
- const rows = r.runs.map((x) => ({ run: `#${x.id}`, title: x.title.slice(0, 60), status: x.status, room: x.room ? `#${x.room}` : "", pr: x.pr ? x.pr.replace(/^https:\/\/github\.com\//, "") : "", updated: short2(x.updatedAt) }));
14123
- return out(r, () => rows.length ? `${table(rows, ["run", "title", "status", "room", "pr", "updated"])}
14135
+ const rows = r.runs.map((x) => ({ run: `#${x.id}`, title: x.title.slice(0, 60), status: x.status, room: x.room ? `#${x.room}` : "", pr: x.pr ? x.pr.replace(/^https:\/\/github\.com\//, "") : "", time: mins(x.durationMin), usd: money(x.usd), updated: short2(x.updatedAt) }));
14136
+ return out(r, () => rows.length ? `${table(rows, ["run", "title", "status", "room", "pr", "time", "usd", "updated"])}
14124
14137
  ${dim(`${t("Detail", "Detalle")}: ghosty factory runs show <run> --workspace ${r.workspace}`)}` : dim(t(`No factory runs in ${r.workspace}.`, `No hay pedidos de la f\xE1brica en ${r.workspace}.`)));
14125
14138
  }
14139
+ if (verb === "stats") {
14140
+ const qs = new URLSearchParams({ since: v.since ?? "30d", ...v.repo ? { repo: v.repo } : {} });
14141
+ const { stats: s2, workspace } = await api(`/api/v2/workspaces/${enc12(ws)}/factory/stats?${qs}`);
14142
+ return out({ workspace, stats: s2 }, () => {
14143
+ if (!s2.runs) return dim(t(`No factory runs in ${workspace} in the last ${s2.sinceDays} days.`, `No hay pedidos de la f\xE1brica en ${workspace} en los \xFAltimos ${s2.sinceDays} d\xEDas.`));
14144
+ return [
14145
+ bold(t(`${workspace} \xB7 last ${s2.sinceDays} days${s2.repo ? ` \xB7 ${s2.repo}` : ""}`, `${workspace} \xB7 \xFAltimos ${s2.sinceDays} d\xEDas${s2.repo ? ` \xB7 ${s2.repo}` : ""}`)),
14146
+ `${t("runs", "pedidos")}: ${s2.runs} \xB7 ${t("merged", "mezclados")}: ${s2.merged} (${s2.mergedPct ?? "\u2014"} %) ${dim(s2.byStatus.map((b) => `${b.status} ${b.runs}`).join(" \xB7 "))}`,
14147
+ `${t("median to PR", "mediana hasta el PR")}: ${mins(s2.medianMinutesToPr)} \xB7 ${t("to merge", "hasta el merge")}: ${mins(s2.medianMinutesToMerge)}`,
14148
+ `${t("@check\u2192@build loops per run", "vueltas @check\u2192@build por pedido")}: ${s2.avgLoops ?? "\u2014"} \xB7 ${t("red CI per run", "CI rojo por pedido")}: ${s2.avgCiFails ?? "\u2014"}`,
14149
+ `${t("cost", "costo")}: ${money(s2.usd)} USD \xB7 ${t("per run", "por pedido")} ${money(s2.usdPerRun)} \xB7 ${bold(t(`per merged PR ${money(s2.usdPerMergedPr)}`, `por PR mezclado ${money(s2.usdPerMergedPr)}`))}`,
14150
+ ...s2.byRepo.length > 1 ? ["", table(s2.byRepo.map((b) => ({ repo: b.repo, runs: b.runs, merged: b.merged, usd: money(b.usd) })), ["repo", "runs", "merged", "usd"])] : []
14151
+ ].join("\n");
14152
+ });
14153
+ }
14126
14154
  if (!ref) throw usage(t("Missing run.", "Falta el pedido."), `ghosty factory runs ${verb} <run> --workspace ${ws}`);
14127
14155
  const path = `${base}/${enc12(ref.replace(/^#/, ""))}`;
14156
+ if (verb === "show" && v.timing) {
14157
+ const { timing: tm, workspace } = await api(`${path}/timing`);
14158
+ return out({ workspace, timing: tm }, () => {
14159
+ const c = tm.clock;
14160
+ const head = [
14161
+ `${bold(`#${tm.run}`)} ${dim(`\xB7 ${tm.status} \xB7 ${t("loops", "vueltas")} ${tm.loops} \xB7 ${t("red CI", "CI rojo")} ${tm.ciFails}`)} \xB7 ${bold(money(tm.usd))} USD`,
14162
+ `${t("clock", "reloj")}: ${mins(c.totalMinutes)} = ${t("working", "trabajando")} ${mins(c.workingMinutes)} \xB7 ${t("waiting for a person", "esperando a una persona")} ${mins(c.waitingHumanMinutes)} \xB7 ${t("other (CI, queues)", "lo dem\xE1s (CI, colas)")} ${mins(c.otherMinutes)}`,
14163
+ dim(c.byState.map((b) => `${b.state} ${mins(b.minutes)}`).join(" \u2192 ")),
14164
+ ""
14165
+ ];
14166
+ const rows = tm.steps.map((s2) => ({
14167
+ [t("at", "hora")]: hhmm(s2.startedAt),
14168
+ [t("step", "paso")]: `@${s2.role ?? "?"}${s2.critic ? t(" (critic)", " (cr\xEDtico)") : ""}${s2.prePlan ? t(" (thread)", " (hilo)") : ""}`,
14169
+ [t("time", "tiempo")]: s2.state === "running" ? `${mins(s2.minutes)} \u2026` : mins(s2.minutes),
14170
+ [t("in tools", "en tools")]: mins(s2.toolMinutes),
14171
+ model: (s2.model ?? "\u2014").replace(/^claude-/, ""),
14172
+ usd: money(s2.usd),
14173
+ [t("state", "estado")]: s2.state === "error" ? red(s2.state) : s2.state
14174
+ }));
14175
+ const cols = Object.keys(rows[0] ?? {});
14176
+ const slow = tm.steps.flatMap((s2) => s2.slow.map((x) => ({ ...x, role: s2.role })));
14177
+ return [
14178
+ ...head,
14179
+ rows.length ? table(rows, cols) : dim(t("No turns found for this run.", "No hay turnos de este pedido.")),
14180
+ ...slow.length ? ["", bold(t("Slowest commands (\u2265 60 s)", "Comandos m\xE1s lentos (\u2265 60 s)")), ...slow.map((x) => ` ${hhmm(x.at)} @${x.role} ${x.secs === null ? red(t("no result", "sin resultado")) : mins(Math.round(x.secs / 6) / 10)} ${dim(`${x.tool}: ${x.input}`)}`)] : [],
14181
+ ...tm.steps.filter((s2) => s2.why).map((s2) => dim(` @${s2.role}: ${t("no timeline", "sin l\xEDnea de tiempo")} (${s2.why})`))
14182
+ ].join("\n");
14183
+ });
14184
+ }
14128
14185
  if (verb === "show") {
14129
14186
  const { run: r } = await api(path);
14130
14187
  const lines = [
@@ -14152,7 +14209,7 @@ ${dim(t("Dry run: nothing changed.", "Simulacro: no se cambi\xF3 nada."))}`);
14152
14209
  const r = await api(path, { body: { title } });
14153
14210
  return out(r, () => `${lavender("\u2713")} ${line2} ${dim(t("(logged; the room card picks it up on its next refresh)", "(queda en bit\xE1cora; la tarjeta del room lo toma en su siguiente refresco)"))}`);
14154
14211
  }
14155
- throw usage(t(`Unknown runs subcommand: ${verb}.`, `Subcomando de runs desconocido: ${verb}.`), 'ghosty factory runs ls | show <run> | rename <run> "title"');
14212
+ throw usage(t(`Unknown runs subcommand: ${verb}.`, `Subcomando de runs desconocido: ${verb}.`), 'ghosty factory runs ls | show <run> [--timing] | stats [--since 30d] | rename <run> "title"');
14156
14213
  }
14157
14214
  async function agentsByHandle(handle, workspace) {
14158
14215
  const qs = new URLSearchParams({ handle, ...workspace ? { workspace } : {} });
@@ -14444,7 +14501,7 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
14444
14501
  staff ls [staff-email] [client-email] Ghosty staff assigned to client accounts (staff) [--all: also revoked]
14445
14502
  staff assign|unassign <staff> <client> Staff sees and runs that account's agents, documents, databases and boards as themselves (no keys, billing or transfers; logged) [--reason]
14446
14503
  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]
14447
- factory runs ls|show|rename A workspace's Software Factory runs: list, detail (plan, PR, preview, who is working), fix a title [--workspace SLUG] [--room R] [--status S]
14504
+ factory runs ls|show|stats|rename A workspace's Software Factory runs: list (time and cost), detail (plan, PR, preview, who is working), where the time and money went, totals, fix a title [--workspace SLUG] [--room R] [--status S] [show --timing] [stats --since 30d --repo R]
14448
14505
 
14449
14506
  ${bold("Agents")}
14450
14507
  agents ls List your agents [--engine E] [--ids: only ids, for xargs] \xB7 --user EMAIL --app all|android|ios|desktop: as their app sees it (staff)
@@ -14608,7 +14665,7 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
14608
14665
  staff ls [correo-staff] [correo-cliente] Staff de Ghosty asignado a cuentas cliente (staff) [--all: tambi\xE9n revocadas]
14609
14666
  staff assign|unassign <staff> <cliente> El staff ve y opera agentes, documentos, bases y tableros de esa cuenta como s\xED mismo (sin llaves, cobro ni traspasos; queda en bit\xE1cora) [--reason]
14610
14667
  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]
14611
- factory runs ls|show|rename Los pedidos de la Software Factory de un espacio: lista, detalle (plan, PR, preview, qui\xE9n trabaja), corregir un t\xEDtulo [--workspace SLUG] [--room R] [--status S]
14668
+ factory runs ls|show|stats|rename Los pedidos de la Software Factory de un espacio: lista (tiempo y costo), detalle (plan, PR, preview, qui\xE9n trabaja), en qu\xE9 se fue el tiempo y el dinero, totales, corregir un t\xEDtulo [--workspace SLUG] [--room R] [--status S] [show --timing] [stats --since 30d --repo R]
14612
14669
 
14613
14670
  ${bold("Agentes")}
14614
14671
  agents ls Lista tus agentes [--engine E] [--ids: s\xF3lo ids, para xargs] \xB7 --user CORREO --app all|android|ios|desktop: como lo ve su app (staff)
@@ -14868,6 +14925,8 @@ async function main() {
14868
14925
  action: { type: "string" },
14869
14926
  verbose: { type: "boolean" },
14870
14927
  full: { type: "boolean" },
14928
+ timing: { type: "boolean" },
14929
+ repo: { type: "string" },
14871
14930
  "as-formmy": { type: "boolean" },
14872
14931
  "key-column": { type: "string" },
14873
14932
  "unset-env": { type: "string" },
@@ -15004,7 +15063,7 @@ async function main() {
15004
15063
  const tokens = splitTokens(pos, v);
15005
15064
  globals.token = tokens.session;
15006
15065
  globals.profile = v.profile;
15007
- if (v.version) return out({ version: "0.54.0" }, () => "0.54.0");
15066
+ if (v.version) return out({ version: "0.55.0" }, () => "0.55.0");
15008
15067
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
15009
15068
  const context = (await readConfig()).workspace;
15010
15069
  if (!explicitToken()?.startsWith("gat_")) {
@@ -15170,7 +15229,7 @@ async function main() {
15170
15229
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
15171
15230
  }
15172
15231
  }
15173
- var notice = updateNotice("0.54.0").catch(() => null);
15232
+ var notice = updateNotice("0.55.0").catch(() => null);
15174
15233
  main().then(
15175
15234
  async () => {
15176
15235
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.54.0",
3
+ "version": "0.55.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": {