@ghostystudio/cli 0.75.0 → 0.76.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
@@ -122,6 +122,7 @@ ghosty connectors ls|connect|disconnect [id] [--q TEXT] [--from-env VAR] [--no-
122
122
  ghosty support open --title T --body TEXT · support ls | show <id> | reply <id> --body TEXT # ask Ghosty for help; answered by email
123
123
  ghosty browser logout # revoke your terminal agents' browser tokens and disconnect Ghosty for Chrome
124
124
  ghosty audit ls [--workspace SLUG] [--agent ID] [--actor EMAIL] [--action A] [--since 24h] [--limit N] # who changed what
125
+ ghosty factory rooms repos # the repos your GitHub App sees, and where they're connected
125
126
  ghosty factory rooms connect owner/name --room R --create # set up the factory for a repo from the terminal
126
127
  ghosty factory run "…" --repo owner/name [--wait] # hand a request to the Software Factory from the terminal
127
128
  ghosty factory runs watch|approve|changes|merge|card <run> # wait for it and decide it without opening Teams
@@ -147,7 +148,7 @@ Exit codes: `0` ok · `1` API error · `2` usage error · `3` not signed in.
147
148
 
148
149
  ### Changes in 0.73.0
149
150
 
150
- - `factory rooms ls|connect|disconnect`: set up the factory for a repo without opening Teams. `connect owner/repo --room R --create` creates the room, connects the repo (only if your GitHub App sees it) and tells you how ready it is for agents.
151
+ - `factory rooms ls|repos|connect|disconnect`: `repos` lists what your GitHub App sees (newest first) and the rooms each repo is in. set up the factory for a repo without opening Teams. `connect owner/repo --room R --create` creates the room, connects the repo (only if your GitHub App sees it) and tells you how ready it is for agents.
151
152
 
152
153
  ### Changes in 0.72.0
153
154
 
package/dist/index.js CHANGED
@@ -1175,7 +1175,7 @@ async function postLong(path, body, timeoutMs = 9e5) {
1175
1175
  const req = httpsRequest(`${base}${path}`, {
1176
1176
  method: "POST",
1177
1177
  timeout: timeoutMs,
1178
- headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.75.0"}`, "content-type": "application/json", "content-length": Buffer.byteLength(data) }
1178
+ headers: { authorization: `Bearer ${token}`, "user-agent": `ghosty-cli/${"0.76.0"}`, "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(path, 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.75.0"}`,
1220
+ "user-agent": `ghosty-cli/${"0.76.0"}`,
1221
1221
  "accept-language": lang(),
1222
1222
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
1223
1223
  ...opts.headers
@@ -11195,7 +11195,7 @@ async function call(path, v, init = {}) {
11195
11195
  "x-ghosty-ts": ts,
11196
11196
  "x-ghosty-sig": sig,
11197
11197
  "content-type": "application/json",
11198
- "user-agent": `ghosty-cli/${"0.75.0"}`
11198
+ "user-agent": `ghosty-cli/${"0.76.0"}`
11199
11199
  },
11200
11200
  body: method === "GET" ? void 0 : raw
11201
11201
  });
@@ -13591,6 +13591,7 @@ var HELPS_ES = {
13591
13591
  ["--yes", "rename, approve, changes, merge: se salta la confirmaci\xF3n (obligatorio sin terminal)"]
13592
13592
  ],
13593
13593
  notes: [
13594
+ "rooms repos lista los repos que ve tu GitHub App (los m\xE1s recientes primero) y en qu\xE9 rooms ya est\xE1 cada uno.",
13594
13595
  "rooms connect revisa que TU instalaci\xF3n de la GitHub App vea el repo (si no, te da la liga para darle acceso) y dice qu\xE9 tan listo est\xE1 para agentes (niveles 1\u20133 y lo que falta). Cualquier miembro puede conectar; desconectar, quien lo conect\xF3 o el due\xF1o. Queda en bit\xE1cora (factory.room_connect / factory.room_disconnect).",
13595
13596
  "run publica \xAB@plan <tu texto>\xBB en el room A TU NOMBRE, como si lo escribieras en Teams: el mismo plan, firmas y tarjeta. Escr\xEDbelo como ticket: el objetivo, por qu\xE9 y c\xF3mo se sabe que qued\xF3. Cualquier miembro puede pedir, firmar, pedir cambios y mergear; todo queda en bit\xE1cora (factory.run, factory.run_approve\u2026).",
13596
13597
  "card baja la tarjeta viva del pedido al final de su hilo; la anterior queda como huella quieta con liga a la viva. Los roles tambi\xE9n pueden (factory_card).",
@@ -14493,6 +14494,7 @@ HELPS.factory = {
14493
14494
  summary: "Hand requests to a workspace's Software Factory from the terminal and decide them (approve the plan, merge the PR) without opening Teams \u2014 the factory as a sidekick for your coding agent. Also its 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 and why it got stuck or failed, totals for the workspace, and fix a run's title.",
14494
14495
  usage: [
14495
14496
  "ghosty factory rooms ls [--full] [--workspace SLUG]",
14497
+ "ghosty factory rooms repos [--workspace SLUG]",
14496
14498
  "ghosty factory rooms connect OWNER/REPO --room R [--create] [--private] [--workspace SLUG]",
14497
14499
  "ghosty factory rooms disconnect OWNER/REPO --room R [--yes]",
14498
14500
  `ghosty factory run "What, why and how we know it's done" --repo OWNER/REPO [--room R] [--wait] [--timeout 1800] [--workspace SLUG]`,
@@ -14532,7 +14534,7 @@ HELPS.factory = {
14532
14534
  ["--yes", "rename, approve, changes, merge: skip the confirmation (required without a terminal)"]
14533
14535
  ],
14534
14536
  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'],
14535
- notes: ["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."],
14537
+ notes: ["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."],
14536
14538
  learn: `${REF}#fabrica`
14537
14539
  };
14538
14540
  function helpText(cmd) {
@@ -15551,7 +15553,19 @@ async function roomsCmd(ws, verb, repo, v) {
15551
15553
  ].join("\n")
15552
15554
  );
15553
15555
  }
15554
- if (verb !== "connect" && verb !== "disconnect") throw usage(t(`Unknown rooms subcommand: ${verb}.`, `Subcomando de rooms desconocido: ${verb}.`), "ghosty factory rooms ls | connect <owner/repo> --room R [--create] [--private] | disconnect <owner/repo> --room R --yes");
15556
+ if (verb === "repos") {
15557
+ const r2 = await api(`${path}?repos=1`);
15558
+ return out(r2, () => {
15559
+ if (!r2.connected) return red(t(`GitHub isn't connected: ${r2.detail ?? "connect it with ghosty connectors connect github"}`, `GitHub no est\xE1 conectado: ${r2.detail ?? "con\xE9ctalo con ghosty connectors connect github"}`));
15560
+ if (!r2.installed) return red(t(`The Ghosty GitHub App isn't installed: ${r2.installUrl ?? ""}`, `La GitHub App de Ghosty no est\xE1 instalada: ${r2.installUrl ?? ""}`));
15561
+ const rows = r2.repos.map((x) => ({ repo: x.repo, rooms: x.rooms.map((s2) => `#${s2}`).join(", ") || dim("\u2014"), private: x.private ? t("yes", "s\xED") : "", pushed: x.pushedAt?.slice(0, 10) ?? "" }));
15562
+ return [
15563
+ rows.length ? table(rows, ["repo", "rooms", "private", "pushed"]) : dim(t("The App doesn't see any repo yet.", "La App todav\xEDa no ve ning\xFAn repo.")),
15564
+ dim(t(`Missing one? Give the App access: ${r2.installUrl ?? ""}`, `\xBFFalta uno? Dale acceso a la App: ${r2.installUrl ?? ""}`))
15565
+ ].join("\n");
15566
+ });
15567
+ }
15568
+ if (verb !== "connect" && verb !== "disconnect") throw usage(t(`Unknown rooms subcommand: ${verb}.`, `Subcomando de rooms desconocido: ${verb}.`), "ghosty factory rooms ls | repos | connect <owner/repo> --room R [--create] [--private] | disconnect <owner/repo> --room R --yes");
15555
15569
  if (!repo) throw usage(t("Missing the repo.", "Falta el repo."), `ghosty factory rooms ${verb} owner/repo --room R --workspace ${ws}`);
15556
15570
  if (!v.room) throw usage(t("Which room?", "\xBFQu\xE9 room?"), t("Add --room NAME (with --create it's made if missing).", "Agrega --room NOMBRE (con --create se crea si no existe)."));
15557
15571
  if (verb === "disconnect") {
@@ -16232,7 +16246,7 @@ ${bold("Workspaces")} ${dim("(changing them: Ghosty staff)")}
16232
16246
  settings ls|set|unset <KEY> [value] Platform switches (staff): who answers /c without an account, native subagents\u2026 [+id/-id edits a list]
16233
16247
  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]
16234
16248
  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]
16235
- factory rooms ls|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]
16249
+ 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]
16236
16250
  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>]
16237
16251
  factory runs ls|show|why|advise|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, why it got stuck or failed, what to do when it's escalated, totals, fix a title [--workspace SLUG] [--room R] [--status S] [show --timing] [why --refresh] [stats --since 30d --repo R]
16238
16252
 
@@ -16431,7 +16445,7 @@ ${bold("Espacios")} ${dim("(cambiarlos: staff de Ghosty)")}
16431
16445
  settings ls|set|unset <CLAVE> [valor] Perillas de la plataforma (staff): qui\xE9n atiende /c sin cuenta, subagentes nativos\u2026 [+id/-id edita una lista]
16432
16446
  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]
16433
16447
  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]
16434
- factory rooms ls|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]
16448
+ 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]
16435
16449
  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>]
16436
16450
  factory runs ls|show|why|advise|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, por qu\xE9 se ator\xF3 o fall\xF3, qu\xE9 hacer si se escal\xF3, totales, corregir un t\xEDtulo [--workspace SLUG] [--room R] [--status S] [show --timing] [why --refresh] [stats --since 30d --repo R]
16437
16451
 
@@ -16897,7 +16911,7 @@ async function main() {
16897
16911
  const tokens = splitTokens(pos, v);
16898
16912
  globals.token = tokens.session;
16899
16913
  globals.profile = v.profile;
16900
- if (v.version) return out({ version: "0.75.0" }, () => "0.75.0");
16914
+ if (v.version) return out({ version: "0.76.0" }, () => "0.76.0");
16901
16915
  for (const n of normalizeArgs(pos, v)) if (!globals.json) info(dim(n));
16902
16916
  const context = (await readConfig()).workspace;
16903
16917
  if (!explicitToken()?.startsWith("gat_")) {
@@ -17092,7 +17106,7 @@ async function main() {
17092
17106
  throw unknown(cmd, cmd, COMMANDS, "ghosty --help");
17093
17107
  }
17094
17108
  }
17095
- var notice = updateNotice("0.75.0").catch(() => null);
17109
+ var notice = updateNotice("0.76.0").catch(() => null);
17096
17110
  main().then(
17097
17111
  async () => {
17098
17112
  const n = await notice;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.75.0",
3
+ "version": "0.76.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": {