@ghostystudio/cli 0.2.1 → 0.4.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 (2) hide show
  1. package/dist/index.js +43 -11
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -275,7 +275,7 @@ async function request(path, opts = {}, retried = false) {
275
275
  method: opts.method ?? (opts.body !== void 0 || opts.raw !== void 0 ? "POST" : "GET"),
276
276
  headers: {
277
277
  authorization: `Bearer ${token}`,
278
- "user-agent": `ghosty-cli/${"0.2.1"}`,
278
+ "user-agent": `ghosty-cli/${"0.4.0"}`,
279
279
  ...opts.body !== void 0 ? { "content-type": "application/json" } : {},
280
280
  ...opts.headers
281
281
  },
@@ -300,8 +300,8 @@ async function toError(res) {
300
300
  if (res.status === 401) return new CliError("Your session is not valid anymore.", EXIT.AUTH, "Run: ghosty login");
301
301
  if (res.status === 403) return new CliError(`Not allowed: ${detail}`, EXIT.API, "Run: ghosty login (to refresh your permissions)");
302
302
  if (res.status === 404) return new CliError("Not found.", EXIT.API, "Check the agent id (ghosty agents ls) or that your token belongs to that agent.");
303
- if (body.error === "agente_sin_maquina") {
304
- return new CliError("This agent's engine has no machine of its own: files, skills, MCP and restart are not available for it.", EXIT.API, "Name, model and prompt can still be changed: ghosty agents set <id> \u2026");
303
+ if (body.error === "restart_no_aplica" || body.error === "agente_sin_maquina") {
304
+ return new CliError("This agent doesn't need a restart: new files, skills and MCP load on its next turn.", EXIT.API);
305
305
  }
306
306
  return new CliError(`${res.status} ${detail}`, EXIT.API);
307
307
  }
@@ -326,6 +326,29 @@ async function agentsLs() {
326
326
  }));
327
327
  out(rows, () => table(rows, ["id", "name", "engine", "lastActivity"]));
328
328
  }
329
+ function parseEnv(raw) {
330
+ if (!raw) return void 0;
331
+ const env = {};
332
+ for (const pair of raw.split(",")) {
333
+ const i = pair.indexOf("=");
334
+ if (i < 1) throw usage(`Bad --env entry: ${pair}.`, "Example: --env GHOSTY_THINKING_EFFORT=max");
335
+ env[pair.slice(0, i).trim()] = pair.slice(i + 1);
336
+ }
337
+ return env;
338
+ }
339
+ async function agentsCreate(v) {
340
+ const name = need(v.name, "--name", "ghosty agents create --name Moon --engine ghosty-lite --model gpt-5.6-luna");
341
+ const body = { name };
342
+ if (v.engine) body.engine = v.engine;
343
+ if (v.model) body.model = v.model;
344
+ if (v.prompt) body.prompt = v.prompt;
345
+ if (v["prompt-file"]) body.prompt = await readFile2(v["prompt-file"], "utf8");
346
+ const env = parseEnv(v.env);
347
+ if (env) body.env = env;
348
+ const r = await api("/api/v2/me/agents", { method: "POST", body });
349
+ out(r, () => `${lavender("\u2713")} Created ${r.name} ${dim(`(${r.engine} \xB7 ${r.model ?? "default"})`)}
350
+ id: ${r.id}`);
351
+ }
329
352
  async function agentsGet(id, fields) {
330
353
  id = need(id, "agent id", "ghosty agents get <agent-id>");
331
354
  const q = fields ? `?fields=${enc(fields)}` : "?full=1";
@@ -335,10 +358,13 @@ async function agentsSet(id, v) {
335
358
  id = need(id, "agent id", "ghosty agents set <agent-id> --prompt-file PROMPT.md");
336
359
  const body = {};
337
360
  if (v.name) body.name = v.name;
361
+ if (v.engine) body.engine = v.engine;
338
362
  if (v.model) body.model = v.model;
339
363
  if (v.prompt) body.prompt = v.prompt;
340
364
  if (v["prompt-file"]) body.prompt = await readFile2(v["prompt-file"], "utf8");
341
- if (!Object.keys(body).length) throw usage("Nothing to change.", "Use --name, --model, --prompt or --prompt-file.");
365
+ const env = parseEnv(v.env);
366
+ if (env) body.env = env;
367
+ if (!Object.keys(body).length) throw usage("Nothing to change.", "Use --name, --engine, --model, --prompt, --prompt-file or --env.");
342
368
  const r = await api(agentPath(id), { method: "PATCH", body });
343
369
  out(r, () => `${lavender("\u2713")} Updated ${Object.keys(body).join(", ")}.`);
344
370
  }
@@ -383,7 +409,7 @@ ${table(r.files ?? [], cols)}`);
383
409
  need(path, "path", ex);
384
410
  const data = v.file ? await readFile2(v.file) : await readStdin();
385
411
  const r = await api(agentPath(id, `/files/${p}`), { method: "PUT", raw: new Uint8Array(data), headers: { "content-type": "application/octet-stream" } });
386
- out(r ?? { path: p, bytes: data.length }, () => `${lavender("\u2713")} Wrote ${p} (${data.length} bytes). Run \`ghosty agents restart ${id}\` if the agent must reload it.`);
412
+ out(r ?? { path: p, bytes: data.length }, () => `${lavender("\u2713")} Wrote ${p} (${data.length} bytes).`);
387
413
  return;
388
414
  }
389
415
  case "rm": {
@@ -411,7 +437,8 @@ async function skillsCmd(sub, id, slug, v) {
411
437
  case "add": {
412
438
  slug = need(slug, "skill slug", ex);
413
439
  const body = v.file ? { markdown: await readFile2(v.file, "utf8") } : { fromCatalog: true };
414
- out(await api(agentPath(id, `/skills/${enc(slug)}`), { method: "PUT", body }), () => `${lavender("\u2713")} Skill ${slug} installed. Run \`ghosty agents restart ${id}\` to load it.`);
440
+ const r = await api(agentPath(id, `/skills/${enc(slug)}`), { method: "PUT", body });
441
+ out(r, () => `${lavender("\u2713")} Skill ${slug} installed.${r?.nota ? dim(` (${r.nota})`) : ""}`);
415
442
  return;
416
443
  }
417
444
  case "rm":
@@ -430,7 +457,8 @@ async function mcpCmd(sub, id, v) {
430
457
  const file = need(v.file, "--file", ex);
431
458
  const parsed = JSON.parse(await readFile2(file, "utf8"));
432
459
  const body = { servers: Array.isArray(parsed) ? parsed : parsed.servers ?? [] };
433
- return out(await api(agentPath(id, "/mcp"), { method: "PUT", body }), () => `${lavender("\u2713")} MCP servers replaced. Run \`ghosty agents restart ${id}\` to load them.`);
460
+ const r = await api(agentPath(id, "/mcp"), { method: "PUT", body });
461
+ return out(r, () => `${lavender("\u2713")} MCP servers replaced \u2014 ${r?.reiniciado ? "the agent restarted with them." : "they load on the next turn."}`);
434
462
  }
435
463
  throw usage(`Unknown mcp subcommand: ${sub ?? "(none)"}.`, ex);
436
464
  }
@@ -699,9 +727,10 @@ ${bold("Session")}
699
727
 
700
728
  ${bold("Agents")}
701
729
  agents ls List your agents
730
+ agents create Create an agent --name [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,\u2026]
702
731
  agents get <id> Show an agent's config [--fields name,model,prompt]
703
- agents set <id> Change identity [--name] [--model] [--prompt | --prompt-file FILE]
704
- agents restart <id> Restart so the next turn loads new files/skills/MCP
732
+ agents set <id> Change identity or engine [--name] [--engine] [--model] [--prompt | --prompt-file FILE] [--env K=V,\u2026]
733
+ agents restart <id> Restart an ACP agent (needsRestart) so it loads new skills
705
734
 
706
735
  ${bold("Configure an agent")}
707
736
  files ls|get|put|rm <id> [path] Files in the agent's machine [--file LOCAL] [--out LOCAL]
@@ -747,6 +776,8 @@ async function main() {
747
776
  fields: { type: "string" },
748
777
  name: { type: "string" },
749
778
  model: { type: "string" },
779
+ engine: { type: "string" },
780
+ env: { type: "string" },
750
781
  prompt: { type: "string" },
751
782
  "prompt-file": { type: "string" },
752
783
  file: { type: "string" },
@@ -765,7 +796,7 @@ async function main() {
765
796
  });
766
797
  globals.json = Boolean(v.json);
767
798
  globals.token = v.token;
768
- if (v.version) return out({ version: "0.2.1" }, () => "0.2.1");
799
+ if (v.version) return out({ version: "0.4.0" }, () => "0.4.0");
769
800
  const [cmd, sub, a1, a2] = pos;
770
801
  if (!cmd || v.help || cmd === "help") return showHelp();
771
802
  switch (cmd) {
@@ -789,10 +820,11 @@ async function main() {
789
820
  }
790
821
  case "agents":
791
822
  if (sub === "ls" || sub === "list" || !sub) return agentsLs();
823
+ if (sub === "create" || sub === "new") return agentsCreate(v);
792
824
  if (sub === "get") return agentsGet(a1, v.fields);
793
825
  if (sub === "set") return agentsSet(a1, v);
794
826
  if (sub === "restart") return agentsRestart(a1);
795
- throw usage(`Unknown agents subcommand: ${sub}.`, "Try: ghosty agents ls | get | set | restart");
827
+ throw usage(`Unknown agents subcommand: ${sub}.`, "Try: ghosty agents ls | create | get | set | restart");
796
828
  case "files":
797
829
  return filesCmd(sub, a1, a2, v);
798
830
  case "skills":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostystudio/cli",
3
- "version": "0.2.1",
3
+ "version": "0.4.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": {