@easybits.cloud/cli 0.21.0 → 0.22.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 +3 -0
  2. package/dist/index.js +102 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -77,6 +77,7 @@ easybits machines secrets ls sb_abc123
77
77
  easybits machines secrets set sb_abc123 --dotenv .env.production # - reads stdin
78
78
  easybits machines secrets unset sb_abc123 DATABASE_URL
79
79
  easybits machines restart shop # restart the app with the current secrets/runspec (no build)
80
+ easybits machines adopt sb_abc123 --name shop-prod --unit app --import-env /app/secrets.env --dry-run # register a box that already runs; its secrets move to the vault
80
81
  easybits machines get shop # tier, size, MXN/month, whether it sleeps
81
82
  easybits machines tiers # the catalog: sizes and prices in MXN
82
83
  easybits machines runspec get shop
@@ -215,6 +216,8 @@ easybits sites ls # your site-builder sites (/dash/sitios): k
215
216
  easybits sites create --prompt "Landing for my dental clinic" # web app (TanStack) in its own machine
216
217
  easybits sites create --prompt "Task tracker with login" --stack next --json
217
218
  easybits sites create --name "Promo" --kind static # CDN website instead of a machine
219
+ easybits sites model my-clinic # engine + model that build it (● = current)
220
+ easybits sites model my-clinic claude-sonnet-5-5 # the model applies to all your sites with that engine
218
221
  easybits sites theme get my-clinic # site by name or id
219
222
  easybits sites theme set my-clinic --theme dracula # or --colors theme.json (every token)
220
223
  easybits websites ls # every static website (also documents and agent-published pages)
package/dist/index.js CHANGED
@@ -2289,6 +2289,7 @@ var REF_ARGS = {
2289
2289
  "db query": { index: 0, kind: "db" },
2290
2290
  "db photos": { index: 1, kind: "db" },
2291
2291
  "sites theme": { index: 1, kind: "site" },
2292
+ "sites model": { index: 0, kind: "site" },
2292
2293
  "fleet get": { index: 0, kind: "fleet" },
2293
2294
  "fleet capabilities": { index: 0, kind: "fleet" },
2294
2295
  "fleet configure": { index: 0, kind: "fleet" },
@@ -2625,6 +2626,39 @@ var machines = {
2625
2626
  emit(ctx, m, () => printMachine(m));
2626
2627
  }
2627
2628
  },
2629
+ adopt: {
2630
+ summary: "Register a box that already runs (e.g. migrated by hand) so its secrets live in the vault",
2631
+ usage: "easybits machines adopt <sandbox-id> --name <name> [--unit <unit>] [--import-env <path-in-box>] [--tier <tier>] [--dry-run]",
2632
+ options: {
2633
+ name: { type: "string", value: "name", description: "Label for the machine" },
2634
+ unit: { type: "string", value: "unit", description: "systemd unit that `machines restart` restarts" },
2635
+ "import-env": { type: "string", value: "path", description: "dotenv file INSIDE the box to copy into the vault (values never leave the server)" },
2636
+ tier: { type: "string", value: "tier", description: "Tier to show for it (default: the host's, or mini)" },
2637
+ "dry-run": { type: "boolean", description: "Show what would happen without writing anything" }
2638
+ },
2639
+ examples: [
2640
+ "easybits machines adopt sb_abc123 --name shop-prod --unit app --import-env /app/secrets.env --dry-run",
2641
+ "easybits machines adopt sb_abc123 --name shop-prod --unit app --import-env /app/secrets.env"
2642
+ ],
2643
+ async run(ctx) {
2644
+ const id = need(ctx, 0, "sandbox-id", this.usage);
2645
+ const name = str(ctx, "name");
2646
+ if (!name) throw usageError(t("Give --name <name>.", "Pasa --name <nombre>."), this.usage);
2647
+ const dryRun = bool(ctx, "dry-run");
2648
+ const r = await api(
2649
+ ctx,
2650
+ "POST",
2651
+ "/machines/adopt",
2652
+ { sandboxId: id, name, unit: str(ctx, "unit"), importEnvFrom: str(ctx, "import-env"), tier: str(ctx, "tier"), dryRun }
2653
+ );
2654
+ emit(ctx, r, () => {
2655
+ console.log(
2656
+ r.dryRun ? t(`Would adopt ${r.sandboxId} as ${r.name} (${r.tier}). Nothing was written.`, `Adoptar\xEDa ${r.sandboxId} como ${r.name} (${r.tier}). No se escribi\xF3 nada.`) : t(`Adopted ${r.sandboxId} as ${r.name}. EasyBits keeps its secrets and restarts it; it never redeploys or releases it.`, `Adoptada ${r.sandboxId} como ${r.name}. EasyBits guarda sus secretos y la reinicia; nunca la redespliega ni la libera.`)
2657
+ );
2658
+ if (r.imported.length) console.log(`${t("Secrets", "Secretos")}: ${r.imported.join(", ")}`);
2659
+ });
2660
+ }
2661
+ },
2628
2662
  restart: {
2629
2663
  summary: "Restart the app's process with the current secrets and runspec (seconds, no build)",
2630
2664
  usage: "easybits machines restart <machine>",
@@ -2796,7 +2830,10 @@ var machines = {
2796
2830
  secrets: {
2797
2831
  summary: "App env vars stored encrypted in your vault",
2798
2832
  usage: SECRETS_USAGE,
2799
- options: { ...ENV_FILE_OPTION },
2833
+ options: {
2834
+ ...ENV_FILE_OPTION,
2835
+ "no-restart": { type: "boolean", description: "Store them without restarting the app (apply later with machines restart)" }
2836
+ },
2800
2837
  examples: [
2801
2838
  "easybits machines secrets ls sb_abc123",
2802
2839
  "easybits machines secrets set sb_abc123 --dotenv .env.production",
@@ -2817,7 +2854,7 @@ var machines = {
2817
2854
  const file = str(ctx, "dotenv");
2818
2855
  const values = { ...file ? await readEnvFile(file, SECRETS_USAGE) : {}, ...pairs(ctx.args.slice(2), SECRETS_USAGE) };
2819
2856
  if (!Object.keys(values).length) throw usageError(t("Give --dotenv <path> (or - for stdin).", "Pasa --dotenv <ruta> (o - para stdin)."), SECRETS_USAGE);
2820
- const r = await eb.machines.setSecrets(id, values);
2857
+ const r = bool(ctx, "no-restart") ? await api(ctx, "PUT", `/machines/${encodeURIComponent(id)}/secrets?restart=false`, values) : await eb.machines.setSecrets(id, values);
2821
2858
  emit(ctx, r, () => console.log(t(`Set ${Object.keys(values).join(", ")}. Injected now: ${r.secretNames.join(", ")}`, `Guardados ${Object.keys(values).join(", ")}. Inyectados ahora: ${r.secretNames.join(", ")}`)));
2822
2859
  } else if (action === "unset") {
2823
2860
  const name = need(ctx, 2, "NAME", SECRETS_USAGE);
@@ -2864,9 +2901,10 @@ function createBody(o, usage2) {
2864
2901
  }
2865
2902
  if (!o.prompt && !o.name) throw usageError(t("Give --prompt (what to build) or --name.", "Pasa --prompt (qu\xE9 construir) o --name."), usage2);
2866
2903
  const body = { kind };
2867
- for (const k of ["prompt", "name", "stack", "template"]) if (o[k]) body[k] = o[k];
2904
+ for (const k of ["prompt", "name", "stack", "template", "engine", "model"]) if (o[k]) body[k] = o[k];
2868
2905
  return body;
2869
2906
  }
2907
+ var MODEL_USAGE = "easybits sites model <site> [<model>] [--engine <id>] [--key <value>]";
2870
2908
  var THEME_USAGE = "easybits sites theme <get|set> <site> [--theme <id> | --colors <file.json|->]";
2871
2909
  async function readColors(path) {
2872
2910
  let text;
@@ -2889,7 +2927,7 @@ var sites = {
2889
2927
  aliases: ["site"],
2890
2928
  group: "Hosting",
2891
2929
  summary: "Your site-builder sites (/dash/sitios): static and web apps",
2892
- synopsis: "sites <ls|create|theme>",
2930
+ synopsis: "sites <ls|create|model|theme>",
2893
2931
  subs: {
2894
2932
  ls: {
2895
2933
  aliases: ["list"],
@@ -2912,13 +2950,15 @@ var sites = {
2912
2950
  create: {
2913
2951
  aliases: ["new"],
2914
2952
  summary: "Create a site from a prompt; its builder agent picks it up in the editor",
2915
- usage: "easybits sites create (--prompt <text> | --name <name>) [--kind webapp|static] [--stack <stack>] [--template <key>]",
2953
+ usage: "easybits sites create (--prompt <text> | --name <name>) [--kind webapp|static] [--stack <stack>] [--template <key>] [--engine <id>] [--model <id>]",
2916
2954
  options: {
2917
2955
  prompt: { type: "string", value: "text", description: "What to build; also names the site if --name is missing" },
2918
2956
  name: { type: "string", value: "name", description: "Site name" },
2919
2957
  kind: { type: "string", value: "kind", description: "webapp (default: its own machine, published later) or static (CDN website)" },
2920
2958
  stack: { type: "string", value: "stack", description: "Web app stack: tanstack (default), next, react-router, remix, nuxt, sveltekit, astro, elysia" },
2921
- template: { type: "string", value: "key", description: "Starting template (tanstack/react-router): consultorio, despacho, portafolio, lanzamiento" }
2959
+ template: { type: "string", value: "key", description: "Starting template (tanstack/react-router): consultorio, despacho, portafolio, lanzamiento" },
2960
+ engine: { type: "string", value: "id", description: "What builds it: claude (your Claude), easybits (included)\u2026 see sites model" },
2961
+ model: { type: "string", value: "id", description: "Model of that engine; applies to all your sites with that engine" }
2922
2962
  },
2923
2963
  examples: [
2924
2964
  'easybits sites create --prompt "Landing for my dental clinic in Puebla"',
@@ -2927,7 +2967,7 @@ var sites = {
2927
2967
  ],
2928
2968
  async run(ctx) {
2929
2969
  const body = createBody(
2930
- { prompt: str(ctx, "prompt"), name: str(ctx, "name"), kind: str(ctx, "kind"), stack: str(ctx, "stack"), template: str(ctx, "template") },
2970
+ { prompt: str(ctx, "prompt"), name: str(ctx, "name"), kind: str(ctx, "kind"), stack: str(ctx, "stack"), template: str(ctx, "template"), engine: str(ctx, "engine"), model: str(ctx, "model") },
2931
2971
  this.usage
2932
2972
  );
2933
2973
  const site = await api(ctx, "POST", "/sites", body);
@@ -2942,6 +2982,46 @@ var sites = {
2942
2982
  });
2943
2983
  }
2944
2984
  },
2985
+ model: {
2986
+ aliases: ["engine"],
2987
+ summary: "See or change what builds a site: engine and model (the model applies to all your sites with that engine)",
2988
+ usage: MODEL_USAGE,
2989
+ options: {
2990
+ engine: { type: "string", value: "id", description: "Switch the site to this engine" },
2991
+ key: { type: "string", value: "value", description: "The engine's key, if your account doesn't have it yet" }
2992
+ },
2993
+ examples: [
2994
+ "easybits sites model my-shop # engines, models and the current one",
2995
+ "easybits sites model my-shop claude-sonnet-5-5",
2996
+ "easybits sites model my-shop --engine easybits"
2997
+ ],
2998
+ async run(ctx) {
2999
+ const id = need(ctx, 0, "site", MODEL_USAGE);
3000
+ const model = ctx.args[1];
3001
+ const engine = str(ctx, "engine");
3002
+ if (!model && !engine) {
3003
+ const [{ items }, { items: mine }] = await Promise.all([
3004
+ api(ctx, "GET", "/sites/engines"),
3005
+ api(ctx, "GET", "/sites")
3006
+ ]);
3007
+ const site = mine.find((s) => s.id === id);
3008
+ emit(ctx, { site: site ? { id: site.id, engine: site.engine } : null, engines: items }, () => {
3009
+ if (site) console.log(t(`${site.name} builds with: ${site.engine}`, `${site.name} se construye con: ${site.engine}`));
3010
+ table(
3011
+ items.flatMap((e) => e.models.map((m) => ({ engine: e.id, model: m.id, label: m.label, now: m.id === e.currentModel ? "\u25CF" : "", key: e.needsSecret ? t("needs key", "pide llave") : "" }))),
3012
+ [["engine", "ENGINE"], ["model", "MODEL"], ["label", "LABEL"], ["now", "NOW"], ["key", "KEY"]]
3013
+ );
3014
+ });
3015
+ return;
3016
+ }
3017
+ const r = await api(ctx, "POST", `/sites/${encodeURIComponent(id)}/engine`, {
3018
+ ...engine ? { engine } : {},
3019
+ ...model ? { model } : {},
3020
+ ...str(ctx, "key") ? { secretValue: str(ctx, "key") } : {}
3021
+ });
3022
+ emit(ctx, r, () => console.log(t(`Now builds with ${r.label} \xB7 ${r.model ?? "default"} (from the next message, on all your ${r.label} sites).`, `Ahora construye con ${r.label} \xB7 ${r.model ?? "default"} (desde el siguiente mensaje, en todos tus sitios con ${r.label}).`)));
3023
+ }
3024
+ },
2945
3025
  theme: {
2946
3026
  summary: "Read or change a site's color theme without a model turn (the \xABTema\xBB button)",
2947
3027
  usage: THEME_USAGE,
@@ -5031,7 +5111,7 @@ async function updateNotice(current2) {
5031
5111
  }
5032
5112
 
5033
5113
  // src/commands/doctor.ts
5034
- var VERSION = true ? "0.21.0" : "dev";
5114
+ var VERSION = true ? "0.22.0" : "dev";
5035
5115
  var doctor2 = {
5036
5116
  name: "doctor",
5037
5117
  group: "Account",
@@ -7371,12 +7451,25 @@ var HELP_ES = {
7371
7451
  "webapp (default: its own machine, published later) or static (CDN website)": "webapp (default: su propia m\xE1quina, se publica despu\xE9s) o static (website en el CDN)",
7372
7452
  "Web app stack: tanstack (default), next, react-router, remix, nuxt, sveltekit, astro, elysia": "Stack de la web app: tanstack (default), next, react-router, remix, nuxt, sveltekit, astro, elysia",
7373
7453
  "Starting template (tanstack/react-router): consultorio, despacho, portafolio, lanzamiento": "Plantilla de partida (tanstack/react-router): consultorio, despacho, portafolio, lanzamiento",
7454
+ "What builds it: claude (your Claude), easybits (included)\u2026 see sites model": "Qu\xE9 lo construye: claude (tu Claude), easybits (incluido)\u2026 ver sites model",
7455
+ "Model of that engine; applies to all your sites with that engine": "Modelo de ese motor; vale para todos tus sitios con ese motor",
7456
+ "See or change what builds a site: engine and model (the model applies to all your sites with that engine)": "Ve o cambia qu\xE9 construye un sitio: motor y modelo (el modelo vale para todos tus sitios con ese motor)",
7457
+ "Switch the site to this engine": "Cambia el sitio a este motor",
7458
+ "The engine's key, if your account doesn't have it yet": "La llave del motor, si tu cuenta todav\xEDa no la tiene",
7459
+ "engines, models and the current one": "motores, modelos y el actual",
7374
7460
  "Read or change a site's color theme without a model turn (the \xABTema\xBB button)": "Lee o cambia el tema de colores de un sitio sin turno del modelo (el bot\xF3n \xABTema\xBB)",
7375
7461
  "Palette id: minimal, calido, oceano, noche, dracula, nord, tokyo-night, github-light\u2026": "Id de la paleta: minimal, calido, oceano, noche, dracula, nord, tokyo-night, github-light\u2026",
7376
7462
  "JSON with every token as #rrggbb (- reads stdin)": "JSON con cada token en #rrggbb (- lee stdin)",
7377
7463
  "edit, then:": "ed\xEDtalo y luego:",
7378
7464
  // machines get/restart/redeploy/backups/backup/runspec/rm/tiers
7379
7465
  "Show a machine: tier, size, price, status and whether it sleeps": "Muestra una m\xE1quina: tier, tama\xF1o, precio, estado y si duerme",
7466
+ "Register a box that already runs (e.g. migrated by hand) so its secrets live in the vault": "Registra una caja que ya corre (p. ej. migrada a mano) para que sus secretos vivan en el vault",
7467
+ "Label for the machine": "Etiqueta de la m\xE1quina",
7468
+ "systemd unit that `machines restart` restarts": "Unit de systemd que reinicia `machines restart`",
7469
+ "dotenv file INSIDE the box to copy into the vault (values never leave the server)": "Archivo dotenv DENTRO de la caja que se copia al vault (los valores no salen del servidor)",
7470
+ "Tier to show for it (default: the host's, or mini)": "Tier con que se muestra (default: el del host, o mini)",
7471
+ "Show what would happen without writing anything": "Muestra qu\xE9 har\xEDa sin escribir nada",
7472
+ "Store them without restarting the app (apply later with machines restart)": "Los guarda sin reiniciar la app (apl\xEDcalos despu\xE9s con machines restart)",
7380
7473
  "Restart the app's process with the current secrets and runspec (seconds, no build)": "Reinicia el proceso de la app con los secretos y el runspec actuales (segundos, sin build)",
7381
7474
  "Build a NEW machine from a release: recover a lost one, or change its tier (resize)": "Construye una m\xE1quina NUEVA desde un release: recupera una perdida o cambia su tier (resize)",
7382
7475
  "Release to build from (default: the machine's newest)": "Release de d\xF3nde construir (default: el m\xE1s nuevo de la m\xE1quina)",
@@ -7777,7 +7870,7 @@ function normalizeArgs(input) {
7777
7870
  }
7778
7871
 
7779
7872
  // src/index.ts
7780
- var VERSION2 = true ? "0.21.0" : "dev";
7873
+ var VERSION2 = true ? "0.22.0" : "dev";
7781
7874
  var GLOBAL_OPTIONS = {
7782
7875
  json: { type: "boolean" },
7783
7876
  token: { type: "string" },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easybits.cloud/cli",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "Official CLI for EasyBits, the cloud for AI agents — sandboxes, hosting, domains, databases, agents and files from your terminal",
5
5
  "type": "module",
6
6
  "bin": {