@miosa/cli 1.1.18 → 1.1.20

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 (50) hide show
  1. package/README.md +0 -21
  2. package/dist/client.d.ts +1 -15
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +44 -118
  5. package/dist/client.js.map +1 -1
  6. package/dist/commands/databases.d.ts.map +1 -1
  7. package/dist/commands/databases.js +33 -10
  8. package/dist/commands/databases.js.map +1 -1
  9. package/dist/commands/devices.js +2 -5
  10. package/dist/commands/devices.js.map +1 -1
  11. package/dist/commands/doctor.d.ts.map +1 -1
  12. package/dist/commands/doctor.js +127 -58
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/sandbox.d.ts.map +1 -1
  15. package/dist/commands/sandbox.js +91 -23
  16. package/dist/commands/sandbox.js.map +1 -1
  17. package/dist/commands/templates.d.ts.map +1 -1
  18. package/dist/commands/templates.js +252 -521
  19. package/dist/commands/templates.js.map +1 -1
  20. package/dist/commands/util.d.ts +0 -1
  21. package/dist/commands/util.d.ts.map +1 -1
  22. package/dist/commands/util.js +2 -15
  23. package/dist/commands/util.js.map +1 -1
  24. package/dist/commands/watch.d.ts.map +1 -1
  25. package/dist/commands/watch.js +1 -5
  26. package/dist/commands/watch.js.map +1 -1
  27. package/dist/config.d.ts +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +4 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/errors.d.ts +2 -18
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +4 -37
  34. package/dist/errors.js.map +1 -1
  35. package/dist/net-diagnosis.d.ts +87 -0
  36. package/dist/net-diagnosis.d.ts.map +1 -0
  37. package/dist/net-diagnosis.js +408 -0
  38. package/dist/net-diagnosis.js.map +1 -0
  39. package/dist/types.d.ts +6 -8
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/types.js.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/api-validation.d.ts +0 -53
  44. package/dist/api-validation.d.ts.map +0 -1
  45. package/dist/api-validation.js +0 -200
  46. package/dist/api-validation.js.map +0 -1
  47. package/dist/endpoint.d.ts +0 -37
  48. package/dist/endpoint.d.ts.map +0 -1
  49. package/dist/endpoint.js +0 -123
  50. package/dist/endpoint.js.map +0 -1
@@ -13,7 +13,7 @@ import { addDataOption, client, apiPath, deleteAndPrint, enc, getAndPrint, postA
13
13
  import { loadConfig } from "../config.js";
14
14
  import { assertDeletableRemoteDir } from "./sandbox-delete-guard.js";
15
15
  import { ENV_FILE_OPTION_HELP, ENV_INLINE_SHELL_WARNING, ENV_STDIN_OPTION_HELP, resolveEnvInputs, } from "./env-input.js";
16
- import { handleError, isJsonMode } from "./util.js";
16
+ import { handleError, isJsonMode, printJson } from "./util.js";
17
17
  import { renderTable } from "../ui/table.js";
18
18
  import { formatDuration, hintBlock, icon, kvPanel, printBanner, printElapsed, } from "../ui/render.js";
19
19
  import { formatBytes } from "../ui/progress.js";
@@ -41,6 +41,72 @@ export function register(program) {
41
41
  .alias("sandboxes")
42
42
  .description("Manage Sandboxes — lightweight code-only Computers (Firecracker microVMs without a desktop)");
43
43
  registerSandboxDevCommands(sandbox);
44
+ // migrate — point a sandbox at a different template version.
45
+ //
46
+ // PREVIEW BY DEFAULT. Migrating replaces the sandbox's root filesystem, so
47
+ // the destructive path is behind an explicit --confirm rather than being what
48
+ // happens when you forget a flag. Ross/HackerAI asked for exactly this shape:
49
+ // a preview of what is preserved, explicit confirmation, the original kept
50
+ // until the replacement is ready, and rollback.
51
+ sandbox
52
+ .command("migrate <id>")
53
+ .description("Preview (default) or perform moving a Sandbox to another template version")
54
+ .requiredOption("--template <ref>", "Target version: v3, <template>@v3, a build id, or 'latest' (latest USABLE version)")
55
+ .option("--confirm", "Actually perform the migration. Without this, nothing is changed.")
56
+ .option("--json", "Output raw JSON")
57
+ .action(async (id, opts) => {
58
+ try {
59
+ const json = isJsonMode(opts);
60
+ const body = {
61
+ template_version: opts.template,
62
+ confirm: Boolean(opts.confirm),
63
+ };
64
+ const res = unwrap(await client().apiPost(apiPath(`/sandboxes/${enc(id)}/migrate`), body));
65
+ if (json) {
66
+ printJson(res);
67
+ return;
68
+ }
69
+ const plan = (res["plan"] ?? res);
70
+ const from = (plan["from"] ?? {});
71
+ const to = (plan["to"] ?? {});
72
+ console.log();
73
+ console.log(` ${chalk.bold("Migration")} ${chalk.dim(str(from["image_id"]))} ${chalk.dim("->")} ${chalk.bold(`v${str(to["version"])}`)} ${chalk.dim(str(to["image_id"]))}`);
74
+ const preserved = (plan["preserved"] ?? []);
75
+ const lost = (plan["lost"] ?? []);
76
+ if (preserved.length > 0) {
77
+ console.log();
78
+ console.log(` ${chalk.green("Preserved")}`);
79
+ for (const p of preserved) {
80
+ console.log(` ${icon.ok} ${str(p["item"])} ${chalk.dim(str(p["detail"]))}`);
81
+ }
82
+ }
83
+ // Printed with the same weight as the preserved list, deliberately.
84
+ // A preview that only shows survivors invites you to assume the rest
85
+ // survives too.
86
+ if (lost.length > 0) {
87
+ console.log();
88
+ console.log(` ${chalk.red("NOT preserved")}`);
89
+ for (const l of lost) {
90
+ console.log(` ${icon.fail} ${str(l["item"])} ${chalk.dim(str(l["detail"]))}`);
91
+ }
92
+ }
93
+ const warnings = (plan["warnings"] ?? []);
94
+ for (const w of warnings) {
95
+ console.log();
96
+ console.log(` ${chalk.yellow("Warning:")} ${w}`);
97
+ }
98
+ console.log();
99
+ if (!opts.confirm) {
100
+ console.log(` ${chalk.dim("Nothing has changed. Re-run with --confirm to perform this migration.")}`);
101
+ }
102
+ else {
103
+ console.log(` ${chalk.dim(str(res["note"]) || "the original Sandbox is preserved until the replacement is ready")}`);
104
+ }
105
+ }
106
+ catch (err) {
107
+ handleError(err);
108
+ }
109
+ });
44
110
  // list
45
111
  sandbox
46
112
  .command("list")
@@ -357,7 +423,7 @@ Note:
357
423
  .option("--no-snapshot", "Deprecated compatibility flag; stop still preserves state server-side")
358
424
  .option("--json", "Output as JSON")
359
425
  .action((id, opts) => runAction(async () => {
360
- const stopped = unwrap(await client().apiPost(apiPath(`/sandboxes/${enc(id)}/pause`), {}));
426
+ const stopped = unwrap(await client().apiPost(apiPath(`/sandboxes/${enc(id)}/stop`), {}));
361
427
  if (isJsonMode(opts)) {
362
428
  console.log(JSON.stringify(stopped, null, 2));
363
429
  return;
@@ -3426,28 +3492,30 @@ function parseSandboxSize(value) {
3426
3492
  throw new UserError(`Invalid sandbox size: ${value}. Expected xs, small, medium, large, or xl.`);
3427
3493
  }
3428
3494
  function resolveSandboxResources(opts) {
3429
- const legacyValues = [opts.cpu, opts.memory, opts.disk];
3430
- const legacyCount = legacyValues.filter((value) => value != null).length;
3431
- if (legacyCount === 0)
3495
+ // No explicit resource flags → just the named size (or small).
3496
+ const anyExplicit = opts.cpu != null || opts.memory != null || opts.disk != null;
3497
+ if (!anyExplicit)
3432
3498
  return { size: opts.size ?? "small" };
3433
- if (legacyCount !== legacyValues.length) {
3434
- throw new UserError("Legacy resource overrides require --cpu, --memory, and --disk together. Prefer --size.");
3435
- }
3436
- const legacy = {
3437
- cpu: opts.cpu,
3438
- memory: opts.memory,
3439
- disk: opts.disk,
3440
- };
3441
- const matchingSize = Object.entries(SANDBOX_SIZE_CONTRACTS).find(([, contract]) => contract.cpu === legacy.cpu &&
3442
- contract.memory === legacy.memory &&
3443
- contract.disk === legacy.disk)?.[0];
3444
- if (!matchingSize) {
3445
- throw new UserError("Legacy --cpu/--memory/--disk values must exactly match a named sandbox size. Prefer --size.");
3446
- }
3447
- if (opts.size && opts.size !== matchingSize) {
3448
- throw new UserError(`Legacy resource overrides match ${matchingSize}, not requested size ${opts.size}.`);
3449
- }
3450
- return { size: matchingSize, legacy };
3499
+ // vCPU and memory are PINS: they must name a real shape. Disk is a FLOOR the
3500
+ // platform grows the rootfs to, so `--disk` overrides it on top of a size.
3501
+ // `--size small --disk 20gb` → a 2 vCPU / 4 GB box with a 20 GB disk.
3502
+ const sizeBase = SANDBOX_SIZE_CONTRACTS[opts.size ?? "small"];
3503
+ const cpu = opts.cpu ?? sizeBase.cpu;
3504
+ const memory = opts.memory ?? sizeBase.memory;
3505
+ const shapeEntry = Object.entries(SANDBOX_SIZE_CONTRACTS).find(([, contract]) => contract.cpu === cpu && contract.memory === memory);
3506
+ if (!shapeEntry) {
3507
+ const shapes = Object.entries(SANDBOX_SIZE_CONTRACTS)
3508
+ .map(([id, c]) => `${id}=${c.cpu}vCPU/${c.memory}MB`)
3509
+ .join(", ");
3510
+ throw new UserError(`--cpu ${cpu} / --memory ${memory} does not match a sandbox shape. ` +
3511
+ `Valid shapes: ${shapes}. (Disk is set separately with --disk.)`);
3512
+ }
3513
+ const shape = shapeEntry[0];
3514
+ if (opts.size && opts.size !== shape) {
3515
+ throw new UserError(`Legacy resource overrides match ${shape}, not requested size ${opts.size}.`);
3516
+ }
3517
+ const disk = opts.disk ?? SANDBOX_SIZE_CONTRACTS[shape].disk;
3518
+ return { size: shape, legacy: { cpu, memory, disk } };
3451
3519
  }
3452
3520
  function parseSizeMb(value) {
3453
3521
  const match = String(value)